工作中有一个功能需求,需要调用对方接口得到数据并更新到数据库中。在网上找了好多没找到有现成的东西,都是单独的批量更新,批量新增。需求要求进行批量处理的时候无则新增,有则更新。

一开始使用的是调用存储过程的方法,在过程中处理这样的操作,但是当数据量过大时事务管理会成为性能的瓶颈。几十上百万的数据频繁更新的时候性能就无法达到要求了,决定想其他的办法。

先声明是oracle数据库,oracle中并没有mysql中replace这样的关键字,后来无意中找到了MERGE INTO 这个关键字。它就是insert和update的合体,这个关键字具体解释网上有很多就不多说了。下边贴出mybatis中sql,各位伙伴如果遇到同样需求可以尝试使用。

<insert id="save表List" parameterType="java.util.List">
 MERGE INTO 要保存的表 T1
 USING 
 (
 <foreach collection="itemList" item="item" index="index" separator="union">
 select #{item.字段1} 字段1, #{item.字段2} 字段2,#{item.字段3} 字段3
   FROM DUAL
   </foreach>
   ) T2
 ON ( T1.字段1=T2.字段1)
 WHEN MATCHED THEN
   UPDATE SET T1.字段2 = T2.字段2, T1.字段3 = T2.字段3
 WHEN NOT MATCHED THEN 
   INSERT (字段1,字段2,字段3) 
   VALUES (T2.字段1, T2.字段2, T2.字段3)  </insert>

首先传入需要批量处理的list在USING中进行循环,之后如果表中有满足 T1.字段1=T2.字段1  这个条件的数据则进行更新,没有则进行新增,需要注意的一点是在ON中的判断的字段不允许在更新中出现,否则会报错。

以上可以满足需要批量进行新增和更新已有数据的操作,具体多少数据提交一次可视情况而定。

另外有一个没有解决的问题,就是当数据中含有大字段的时候比如clob字段字符过长会有报错,因为oracle中不允许两个单引号之间的长度超过4000,这块暂时还没有解决兼容的方法就是在构建list的时候判断一下这个字段是不是过长,如果过长的话还是利用存储过程这样的方式单独处理。