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存储过程的解决方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

时间: 2017-03-08

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传入参数的实例代码

在MyBatis的select.insert.update.delete这些元素中都提到了parameterType这个属性.MyBatis现在可以使用的parameterType有基本数据类型和JAVA复杂数据类型 基本数据类型:包含int,String,Date等.基本数据类型作为传参,只能传入一个.通过#{参数名} 即可获取传入的值 复杂数据类型:包含JAVA实体类.Map.通过#{属性名}或#{map的KeyName}即可获取传入的值 基本数据类型参数示例: 根据班级ID查询教师列表 x

mybatis动态sql之Map参数的讲解

mybatis 动态sql之Map参数 Mapper文件: <mapper namespace="com.cn.shoje.oa.modules.logistics.dao.PurcDao"> <select id="findAll" parameterType="Map" resultType="Purchase"> select * from prod_purchase where 1=1 <

MyBatis传入数组集合类并使用foreach遍历

这篇文章主要介绍了MyBatis传入数组集合类并使用foreach遍历,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 在mapper中传入数组或集合类,使用foreach标签遍历出其中的值与SQL语句拼接 JAVA dao层接口 public interface UserDao { public List<User> getUsersByCollection(Collection collection); } mapper文件 <sel

JAVA 区分集合和数组

数组和集合的定义: 数组: 数组是java语言内置的数据类型,他是一个线性的序列,所有可以快速访问其他的元素,数组和其他语言不同,当你创建了一个数组时,他的容量是不变的,而且在生命周期也是不能改变的,还有JAVA数组会做边界检查,如果发现有越界现象,会报RuntimeException异常错误,当然检查边界会以效率为代价. 集合: JAVA还提供其他集合,list,map,set,他们处理对象的时候就好像这些对象没有自己的类型一样,而是直接归根于Object,这样只需要创建一个集合,把对象放进去

Java集合与数组区别简介及相互转换实例

数组Array和集合的区别: (1)数组是大小固定的,并且同一个数组只能存放类型一样的数据(基本类型/引用类型) (2)JAVA集合可以存储和操作数目不固定的一组数据.(3)若程序时不知道究竟需要多少对象,需要在空间不足时自动扩增容量,则需要使用容器类库,array不适用. 联系:使用相应的toArray()和Arrays.asList()方法可以回想转换. List和ArrayList的区别 1.List是接口,List特性就是有序,会确保以一定的顺序保存元素. ArrayList是它的实现类

java8新特性 stream流的方式遍历集合和数组操作

前言: 在没有接触java8的时候,我们遍历一个集合都是用循环的方式,从第一条数据遍历到最后一条数据,现在思考一个问题,为什么要使用循环,因为要进行遍历,但是遍历不是唯一的方式,遍历是指每一个元素逐一进行处理(目的),而并不是从第一个到最后一个顺次处理的循环,前者是目的,后者是方式. 所以为了让遍历的方式更加优雅,出现了流(stream)! 1.流的目的在于强掉做什么 假设一个案例:将集合A根据条件1过滤为子集B,然后根据条件2过滤为子集C 在没有引入流之前我们的做法可能为: public cl

Mybatis传入List实现批量更新的示例代码

Dao层写法 /** * 批量更新新库存 * @param list * @return */ int updateNewStock(@Param(value = "list") List<GreenBeanMsg> list); xml具体实现代码 <update id="updateNewStock" parameterType="java.util.List"> <foreach collection=&quo

JavaScript 数据元素集合与数组的区别说明

其中getElementsByName(name)方法是获取页面中所有具有name属性的元素,但这个方法在IE与标准浏览器中所取到的内容不一样.在IE中getElementsByName(name)方法所取到的元素是其本身就自带有name属性也就是form表单中所列出的所有元素(这些元素本身就自带有name属性):标准浏览器中getElementsByName(name)方法所取到的元素是具有name属性的元素(本身就带有此属性+人为添加的此属性).所以如果在IE浏览器中用此方法来获取页面中所有

java实现列表、集合与数组之间转化的方法

本文实例讲述了java实现列表.集合与数组之间转化的方法.分享给大家供大家参考.具体实现方法如下: 复制代码 代码如下: package test;  import java.util.ArrayList;  import java.util.Arrays;  import java.util.HashSet;  import java.util.List;  import java.util.Set;  public class Test2 {      public static void