温故而知新,这里记录一下
批量插入时,xxxMapper.java 中方法的参数都必须是 List ,泛型可以是 bean ,也可以是 Map 。配合使用 mybatis 的 foreach 即可。示例如下:
public Integer batchInsertDemo(List list);
首先对于批量数据的插入有两种解决方案
1、for 循环调用 Dao 中的单条插入方法
2、传一个 List
insert into user(name,age) values
(#{item.name},#{item.age})
性能上对比,批量插入性能好,更加省时间。
原因如下:
这种写法适合插入数据的项不变,即 sql 中 VALUES 前括号中的列不变。若插入的项有所变化则适用下一种方法。
INSERT INTO demo(id,name,code,age,address)
VALUES
(#{item.id},#{item.name},#{item.code},#{item.age},#{item.address})
此时需适用 foreach 循环包含整个sql语句,VALUES 前后括号中的插入项和插入数据使用 trim 标签,再配合使用 if 标签即可。示例如下:
INSERT INTO demo
id,
name,
code,
age,
address,
if test="item.id!= null">
#{item.id,jdbcType=INTEGER},
#{item.name,jdbcType=VARCHAR},
#{item.code ,jdbcType=VARCHAR},
#{item.age,jdbcType=INTEGER},
#{item.address,jdbcType=VARCHAR},
例的建表语句是:
-- auto-generated definition
create table contact_type
(
sid varchar(50) not null
primary key,
name varchar(50) default '' null,
status int default 1 null comment '状态,默认1表示有效,0为冻结',
seq float default 0 null,
create_time datetime default CURRENT_TIMESTAMP null
)
comment '往来单位类型';
所以主键是字符串类型,而不是自增类型。写在 Mybatis 的 xml 文件中的SQL语句如下:
insert into contact_type
create_time,
name,
seq,
sid,
status,
values
#{create_time},
#{name},
#{seq},
#{sid},
#{status},
ON DUPLICATE KEY UPDATE
create_time = #{create_time},
name = #{name},
seq = #{seq},
sid = #{sid},
status = #{status},
可以看到由于使用了
测试表创建的主键字段非自增,所以将上面 xml 中的头部 SQL 语句(返回新增行的主键字段值)给注释掉了,如果你的表示有自增字段的去掉注释,即可得到新增的行的自增字段数值。
通过在 java 中测试,发现上面的语句新增一行成功后会返回1,修改成功后会返回2(这里有疑惑,如果清楚原因的麻烦跟帖科普下)。
如果有未设置的属性恰好在数据库端对应的字段被设置为非空并且没有默认值导致新增或者修改失败那么会报异常 java.sql.SQLException 。
批量写入数据有则修改无则新增,同时判断空选择性写入字段
数据表还是上面的,直接贴出写在 Mybatis 的 XML 文件中的 SQL 是:
insert into contact_type
create_time,
name,
seq,
sid,
status,
values
#{ele.create_time},
#{ele.name},
#{ele.seq},
#{ele.sid},
#{ele.status},
ON DUPLICATE KEY UPDATE
create_time = #{ele.create_time},
name = #{ele.name},
seq = #{ele.seq},
sid = #{ele.sid},
status = #{ele.status},
上面代码中在 SQL 语句的最外层使用了 for 循环,好处是将 List
例子3
insert into com_coment
domain,
status,
gmt_created,
gmt_modified,
#{domain,jdbcType=INTEGER},
#{status,jdbcType=INTEGER},
#{gmtCreated,jdbcType=TIMESTAMP},
#{gmtModified,jdbcType=TIMESTAMP},
MySQL默认接受sql的大小是1048576(1M),即第三种方式若数据量超过1M会报如下异常:(可通过调整MySQL安装目录下的my.ini文件中[mysqld]段的"max_allowed_packet = 1M")
nested exception is com.mysql.jdbc.PacketTooBigException: Packet for query is too large (5677854 > 1048576).
You can change this value on the server by setting the max_allowed_packet' variable.
由于上面的 SQL 在数据库端是多条语句,需要在 Java 连接数据库的字串中设置 &allowMultiQueries=true
对于普通的单条插入,数据库的返回值就是 (0/1) 。
对于返回值代表的意思可以认为是“语句执行返回的数据库受影响的行数。”或者是“此次执行是否成功(0 - 失败,1 - 成功)。”
对应的也就是在 Dao 层中,对于插入方法的返回值类型的设定有(int/boolean)两种。
对于批量插入的返回值,返回的还是(0/1), 而不是统计插入成功几条,即使你的 Dao 层方法的返回值类型为 int.
这里的(0/1) 也就代表着,这次批量插入是否成功(0 - 失败,1 - 成功)。
当然你 Dao 层的返回值还是可以是(int/boolean)
猜想有下面三种情况
这里就直接放结果了。
关于测试过程可以看这篇博客:mysql 批量插入语句执行失败的话,是部分失败还是全部失败
其实也很好理解。
首先我们知道了 MyBatis
就相当于咱们自己在 MySQL 的命令行中,执行一条多插入的语句。默认情况下 MySQL 单条语句是一个事务,这在一个事务范围内,当中间的 SQL 语句有问题,或者有一个插入失败,就会触发事务回滚。同时你也能看到错误提示。(命令行执行单条 SQL 的情况)
所以有一个插入不成功肯定全部回滚。
我这里就直接放结论,又兴趣的可以看这篇博客有探究过程 : Mybatis 批量插入引发的血案
1、MyBatis 本身对插入的数据量没有限制
2、MySQL 对语句的长度有限制,默认是 4M
其他数据库的情况这里不介绍,可以自行百度。通过上面 “MySQL 对语句的长度有限制,默认是 4M” 我们可以知道,批量插入数据是有限制的。不能一下把几万条数据(就是太大数据量意思)一次性插入。
所以一般情况下我们推荐即使使用批量插入,也要分批次。
每次批次设置多少?需要根据你的插入一条数据的参数量来做度量。因为受限条件是 SQL 语句的长度。
而且分批插入更加合理,对于插入失败,回滚范围会缩小很多。
MyBatis 并没有做集合容量的验证,如果集合参数为空或者 size 为 0 则生成的 SQL 可能只有”insert into user (name,age) values” 这样一段或者没有,所以说,写批量 SQL 的时候注意在调用批量方法的地方加入对容量的验证。
insert into user(name,age) values(#{item.name},#{item.age})
这种写法也能实现批量插入。但是有很多问题。
所以如果你想中间插入失败回滚的话,需要使用 Spring 事务,但是还需要注意 spring 事务是抛出运行时异常时才会回滚。这种批量插入中间有没插入成功的是不会抛出异常的。所以你需要根据返回值判断手动编码抛出异常。
而最上面的那种写法就不用是用事务,因为他是一条 SQL 语句。
foreach 的主要用在构建 in 条件中,它可以在 SQL 语句中进行迭代一个集合。
foreach 元素的属性主要有 item,index,collection,open,separator,close。 item 表示集合中每一个元素进行迭代时的别名 index 指定一个名字,用于表示在迭代过程中,每次迭代到的位置 open 表示该语句以什么开始 separator 表示在每次进行迭代之间以什么符号作为分隔符 close 表示以什么结束
在使用 foreach 的时候最关键的也是最容易出错的就是 collection 属性,该属性是必须指定的,但是在不同情况 下,该属性的值是不一样的,主要有一下 3 种情况:
Mybatis 批量插入数据 SQL-腾讯云开发者社区-腾讯云
Mybatis 批量写入有则修改无则新增,同时判断空选择性写入字段_mybatis批量新增并且判断空-CSDN博客
https://www.cnblogs.com/fantastic-clouds/p/13090557.html
MyBatis 批量插入 - Yaxing's Blog