Mybatis传list参数调用oracle存储过程的解决方法

怎么利用MyBatis传List类型参数到数据库存储过程中实现批量插入数据?

MyBatis中参数是List类型时怎么处理?大家都知道MyBatis批处理大量数据是很难做到事务回滚的(事务由Spring管理),都将逻辑写在存储中又是及其头疼的一件事(参数长度也有限制),那么我想的是将参数在后台封装为单个或多个list集合,直接通过MyBatis将此参数传到数据库存储过程中,一来摆脱了MyBatis批量插入数据的诸多限制(例如:不能实时返回主键、foreach标签循环集合长度有限制),二来就是在存储中灵活的控制事务,但是这又会涉及两个问题,MyBatis的xml文件中该怎么封装,利用BaseTypeHandler吗?

对于这个问题,经过一天的研究终于算是跑通了,说一下解决办法:

1.建立数据库表,大家应该都有自己的库表了,所以这一步基本上就可以跳过了。我之所以在这里把库表贴出来是为了让大家对应里面的参数。

数据库表:

create table ZD_UNIT_MENU
(
 unit_id VARCHAR2(32),
 menu_id VARCHAR2(32)
) 

2.在数据库中建立相应的java对象(Oracle中的类型)和数组:

CREATE OR REPLACE TYPE unit_menu_obj AS OBJECT(
 unitId VARCHAR2(32),
 menuId VARCHAR2(32)
);
CREATE OR REPLACE TYPE unit_menu_table AS table OF unit_menu_obj; 

3.存储过程:

create or replace procedure save_unit_power(list0 in unit_menu_table,result0 out int) as
 sql_bind varchar(200);
begin
 FOR i IN 1 .. list0.count LOOP
  sql_bind := 'insert into ZD_UNIT_MENU(UNIT_ID,MENU_ID) values('''||list0(i).unitId||''', '''||list0(i).menuId||''' )';
  execute immediate sql_bind;
 end loop;
 commit;
 --返回结果,执行成功的话返回1
 result0 := 1;
 --捕捉异常,回滚操作
 EXCEPTION
   WHEN OTHERS THEN
     result0 := -1;--执行失败的话返回-1
   ROLLBACK;
end save_unit_power;

4.再看看mybatis的配置吧:

<parameterMap type="java.util.Map" id="_map">
    <parameter property="list0" jdbcType="ARRAY"
      javaType="java.util.List" mode="IN" typeHandler="com.zd.util.ListHandler"/>
    <parameter property="result0" jdbcType="DECIMAL"
      javaType="java.lang.Integer" mode="OUT" />
 </parameterMap>
 <select id="addUnitPower" statementType="CALLABLE" parameterMap="_map">
    <![CDATA[
    CALL save_unit_power(?,?)
    ]]>
 </select> 

5.看看我是如何调用的?我直接贴我的server代码了,dao层的就没必要了:

List<UnitMenu> list = new ArrayList<UnitMenu>();
  Map<String, Object> _map = new HashMap<String, Object>();
  String[] menuIds = menuTreeIds.split(",");
  JSONObject job = new JSONObject();
  int result = -1;
  for(int i = 0; i < menuIds.length; i++){
    UnitMenu um = new UnitMenu();
    um.setMenuId(menuIds[i]);
    um.setUnitId(unitId);
    list.add(um);
  }
  _map.put("list0", list);
  _map.put("result0", "");
  unitMenuMapper.addUnitPower(_map);
  System.out.println("================================================_map = "+_map.toString());
  result = (Integer)_map.get("result0");
  System.out.println("================================================result = "+result); 

6.非常关键的一点儿,细心的人应该会注意到,在mapper.xml配置中,有typeHandler配置,里面配置的实际上是我写的一个类,这个类的作用就是讲java中的list转换成数据库中我们建立的对象和数组,看代码吧:

package com.zd.util;
 import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import oracle.sql.ARRAY;
import oracle.sql.ArrayDescriptor;
import oracle.sql.STRUCT;
import oracle.sql.StructDescriptor;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import com.zd.model.system.UnitMenu;
public class ListHandler extends BaseTypeHandler{
  @Override
  public Object getNullableResult(ResultSet arg0, String arg1)
      throws SQLException {
    // TODO Auto-generated method stub
    return null;
  }
  @Override
  public Object getNullableResult(CallableStatement arg0, int arg1)
      throws SQLException {
    // TODO Auto-generated method stub
    return null;
  }
  @SuppressWarnings("unchecked")
  @Override
  public void setNonNullParameter(java.sql.PreparedStatement parameterSetter, int i,
      Object o, JdbcType jdbcType) throws SQLException {
    Connection conn = null;
    try {
      if(null != o){
        List<UnitMenu> list = (ArrayList<UnitMenu>) o;
        conn = DriverManager.getConnection("jdbc:oracle:thin:@192.168.1.88:1521:orcl", "tctscm", "tctscm");
        //这里必须得用大写,而且必须要引入一个包,如果不引入这个包的话字符串无法正常转换,包是:orai18n.jar
        ARRAY array = getArray(conn, "UNIT_MENU_OBJ", "UNIT_MENU_TABLE", list);
        parameterSetter.setArray(i, array);
      }
    } catch (Exception e) {
      e.printStackTrace();
    } finally{
      if(null != conn){
        conn.close();
      }
    }
  }
  @SuppressWarnings("rawtypes")
  private ARRAY getArray(Connection con,String OracleObj, String Oraclelist, List<UnitMenu> listData) throws Exception {
    ARRAY array = null;
    ArrayDescriptor desc = ArrayDescriptor.createDescriptor(Oraclelist, con);
    STRUCT[] structs = new STRUCT[listData.size()];
    if (listData != null && listData.size() > 0){
      StructDescriptor structdesc = new StructDescriptor(OracleObj, con);
      for (int i = 0; i < listData.size(); i++){
        Object[] result = {listData.get(i).getUnitId(),listData.get(i).getMenuId()};
        structs[i] = new STRUCT(structdesc, con, result);
      }
      array = new ARRAY(desc, con, structs);
    }else{
      array = new ARRAY(desc, con, structs);
    }
    return array;
  }
} 

以上所述是小编给大家介绍的Mybatis传list参数调用oracle存储过程的解决方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • Mybatis 传输List的实现代码

    1. 当查询的参数只有一个时 findByIds(List<Long> ids) 1.1 如果参数的类型是List, 则在使用时,collection属性要必须指定为 list Xml代码 <select id="findByIdsMap" resultMap="BaseResultMap"> Select <include refid="Base_Column_List" /> from jria where

  • MyBatis传入集合 list 数组 map参数的写法

    foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合.foreach元素的属性主要有item,index,collection,open,separator,close.item表示集合中每一个元素进行迭代时的别名,index指定一个名字,用于表示在迭代过程中,每次迭代到的位置,open表示该语句以什么开始,separator表示在每次进行迭代之间以什么符号作为分隔符,close表示以什么结束,在使用foreach的时候最关键的也是最容易出错的就是collection属性

  • Mybatis传list参数调用oracle存储过程的解决方法

    怎么利用MyBatis传List类型参数到数据库存储过程中实现批量插入数据? MyBatis中参数是List类型时怎么处理?大家都知道MyBatis批处理大量数据是很难做到事务回滚的(事务由Spring管理),都将逻辑写在存储中又是及其头疼的一件事(参数长度也有限制),那么我想的是将参数在后台封装为单个或多个list集合,直接通过MyBatis将此参数传到数据库存储过程中,一来摆脱了MyBatis批量插入数据的诸多限制(例如:不能实时返回主键.foreach标签循环集合长度有限制),二来就是在存

  • 从js向Action传中文参数出现乱码问题的解决方法

    做项目的时候,发现Action获取jsp表单中的中文参数,只要整个项目都采用UTF-8编码格式都不会出现乱码问题:但JSP中用到JS,并从JS向Action传中文参数,就会出现中文乱的现象.几经询问百度,上面说法很多. 经过实践发现下面的方法可以解决中文乱码问题: JSP的JS中:中文参数用encodeURI(encodeURI(中文参数)),经过两次转码.例如: 复制代码 代码如下: function show(next,id,realName){ document.forms['f2'].a

  • Mybatis调用Oracle存储过程的方法图文详解

    1:调用无参数的存储过程. 创建存储过程: Mapper.xml 配置:经测试其他标签(update.insert.select)也可以. Mapper.java MapperTest.java 测试 2:有参数的存储过程调用: 2.1存储过程的创建: 2.2Mapper.xml 的配置: 2.3Mapper.java 2.4MapperTest.java 测试 控制台输出: 3:存储过程的结果集调用. 3.1创建存储过程: 3.2 Mapper.xml 配置 配置 resultMap结果集字段

  • mybatis 调用 Oracle 存储过程并接受返回值的示例代码

    目录 存储过程 mapper.xml dao层 调用 存储过程 PROCEDURE P_TEST_MYBATIS(iv_ins1 IN VARCHAR2, --id iv_ins2 IN VARCHAR2, --no ov_res OUT number --提示信息 ) IS BEGIN ov_res := 0; select count(1) into ov_res from jc_zhiydoc t where t.zhiy_id = iv_ins1 and t.zhiy_no = iv_i

  • Java调用Oracle存储过程详解

    Java调用Oracle存储过程详解 步骤: 1.编写Oracle存储过程 2.编写数据库获取连接工具类 3.编写简单应用调用存储过程 实现: 1.Oracle存储过程: /*测试表*/ create table test( id varchar2(32), name varchar2(32) ); /*存储过程 插入数据*/ CREATE OR REPLACE PROCEDURE insert_procedure( PARA1 IN VARCHAR2, PARA2 IN VARCHAR2 )

  • asp.net中调用oracle存储过程的方法

    存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的SQL 语句集,存储在数据库中经过第一次编译后再次调用不需要再次编译,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它. 存储过程是数据库中的一个重要对象,任何一个设计良好的数据库应用程序都应该用到存储过程. 不多说了,本文通过两种方法介绍asp.net中调用oracle存储过程的方法,具体内容请看下面代码. 调用oracle存储过程方法一: ORACLE代码 CREATE OR REP

  • C#调用Oracle存储过程方法介绍(附源码)

    C#调用Oracle存储过程的代码如下所示: using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Configuration; using System.Data; using System.Data.OracleClient; using System.Drawing; using Syste

  • Python使用cx_Oracle调用Oracle存储过程的方法示例

    本文实例讲述了Python使用cx_Oracle调用Oracle存储过程的方法.分享给大家供大家参考,具体如下: 这里主要测试在Python中通过cx_Oracle调用PL/SQL. 首先,在数据库端创建简单的存储过程. create or replace procedure test_msg(i_user in varchar2, o_msg out varchar2) is begin o_msg := i_user ||', Good Morning!'; end; 然后,开始在Pytho

  • C#调用Oracle存储过程的方法

    本文实例讲述了C#调用Oracle存储过程的方法.分享给大家供大家参考.具体实现方法如下: Oracle数据库代码如下: 复制代码 代码如下: create or replace procedure proce_test(paramin in varchar2,paramout out varchar2,paraminout in out varchar2) as   varparam varchar2(28); begin   varparam:=paramin;   paramout:=va

  • Spring boot调用Oracle存储过程的两种方式及完整代码

    前言 因工作需要将公司SSH项目改为Spingboot项目,将项目中部分需要调用存储过程的部分用entityManagerFactory.unwrap(SessionFactory.class).openSession()来获取Session实现后发现项目访问数据库超过十次就会挂掉,原因是Springboot连接池数量默认为10,猜测是每次访问数据库后连接未释放导致的,手动关闭session后问题解决. 解决问题的过程中又发现了另外两种调用方式: 直接用EntityManager的createS

随机推荐