前言:前段时间做了个批量插入功能,数据库用的Oracle当时只写了10来个测试数据没问题就没管,但是今天转正式数据时(正式数据804条)发现批量插入报错java.sql.SQLException: ORA-24335: 无法支持 1000 列以上,以下为问题复现、原因、解析和解决,特此记录。
复现:mybatis语句如下
<insert id="insertSeats" parameterType="java.util.List">
insert all
<iterate conjunction=" ">
into CONFERENCE_SEAT
(ID,
CONFERENCEID,
SEQ,
SEATNO,
NAME,
OFFICE,
TYPE)
values
<![CDATA[
(#list[].ID:VARCHAR#,
#list[].CONFERENCEID:VARCHAR#,
#list[].SEQ:VARCHAR#,
#list[].SEATNO:VARCHAR#,
#list[].NAME:VARCHAR#,
#list[].OFFICE:VARCHAR#,
#list[].TYPE:VARCHAR#)
]]>
</iterate>
select * from dual
</insert>
原因:插入的参数或语句字段超长。
解释:首先导致报错的原因跟mybatis无关,而是跟数据库有关,再看报错信息“无法支持 1000 列以上”,这里的“列”并不是值得数据库中表的列,不同数据库不一样,以下列出三种为例:
1.Oracle:该数据库大多规定所执行批量插入的参数不能超过1000(这个限制不同版本可能不同);可以看出复现sql中一次插入了7个,所以其实再插入第143条数据的时候就超过限制抛出异常。
2.SQLServer:该数据库规定同Oracle一样,也是对参数个数进行了限制,参数限制基本上也是1000,超过个数SQLServer的JDBC包会抛出异常。
3.Mysql:该数据库为最常用数据库,对批量插入也有限制,但是限制跟以上两个数据不同,该数据库限制的是字符大小,以我目前用的mysql5.0版本为例,可以用select @@max_allowed_packet 查询一下,我的显示1048576 也就是1M,也就是说假设执行批量插入一条数据的语句的sql如果字符长度达到1024,在执行第1025次循环插入时就会抛出异常。
解决:这里说下Oracle 和Mysql的解决办法;
-
对于oracle来说,本人采取的解决办法并没有去对数据库配置进行修改,修改是肯定有办法修改的,但是这个没有太过研究,只是修改了sql进行单条插入,后台执行了循环遍历调用,为了提升用户体验把循环方法做成了异步处理,可能会牺牲一些性能吧,但是考虑本身不是高并发项目也就不用那么顾虑了。
-
对于mysql来说,就可以进行数据库配置修改,语句:set GLOBAL max_allowed_packet = 4194304 修改完毕重启客户端即可。
附:网上很多人说换高版本数据库,不得不说这个方法有时候灵,有时候不灵,原因是高版本数据库可能限制不会那么高,这种解决办法纯属侥幸!!