Mybatis 批量操作8种实现总结
批量新增
1.方式一(常用)
<!-- 批量新增-->
<insert id="batchSave" parameterType="java.util.List">INSERT INTO lp_user_test_batch(id,user_id,user_name,user_age,type,create_time,update_time)VALUES<foreach collection="list" item="item" index="index" separator=",">(#{item.id,jdbcType=BIGINT},#{item.userId,jdbcType=VARCHAR},#{item.userName,jdbcType=VARCHAR},#{item.userAge,jdbcType=INTEGER},#{item.type,jdbcType=INTEGER},#{item.createTime,jdbcType=TIMESTAMP},#{item.updateTime,jdbcType=TIMESTAMP})</foreach>
</insert>
测试结果
数量 | 耗时 |
---|---|
1000 | 1469ms |
2000 | 2534ms |
3000 | 2613ms |
4000 | 3549ms |
5000 | 4733ms |
8000 | 5761ms |
10000 | 6055ms |
2.方式二
批量新增或更新方式
注:需要给唯一主键添加唯一索引,update才会生效
<!-- 批量新增或更新-->
<insert id="batchSaveOrUpdate" parameterType="java.util.List">INSERT INTO lp_user_test_batch(id,user_id,user_name,user_age,type,create_time,update_time)VALUES<foreach collection="list" item="item" index="index" separator=",">(#{item.id,jdbcType=BIGINT},#{item.userId,jdbcType=VARCHAR},#{item.userName,jdbcType=VARCHAR},#{item.userAge,jdbcType=INTEGER},#{item.type,jdbcType=INTEGER},#{item.createTime,jdbcType=TIMESTAMP},#{item.updateTime,jdbcType=TIMESTAMP})</foreach>ON DUPLICATE KEY UPDATEuser_name = VALUES(user_name),user_age = VALUES(user_age),type = VALUES(type),update_time = VALUES(update_time)
</insert>
测试结果
数量 | 耗时 |
---|---|
1000 | 1692ms |
2000 | 2346ms |
3000 | 3249ms |
4000 | 3443ms |
5000 | 3999ms |
8000 | 6460ms |
10000 | 7053ms |
3.方式三
单条sql+批量方式的SqlSession
<insert id="insert" >INSERT INTO lp_user_test_batch(id,user_id,user_name,user_age,type,create_time,update_time)values(#{id,jdbcType=BIGINT},#{userId,jdbcType=VARCHAR},#{userName,jdbcType=VARCHAR},#{userAge,jdbcType=INTEGER},#{type,jdbcType=INTEGER},#{createTime,jdbcType=TIMESTAMP},#{updateTime,jdbcType=TIMESTAMP})
</insert>
@Resource(name = "sqlSessionFactory")
private SqlSessionFactory sqlSessionFactory;/*** 利用 MyBatis 批处理特性,批量提交*/
public void batchInsert(List<UserTestBatchDO> testBatchDAOList) {//集合非空if (CollectionUtils.isEmpty(testBatchDAOList)) {return;}//批处理方式 SqlSessionSqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);//获得对应的MapperUserTestBatchDOMapper userTestBatchDOMapper = sqlSession.getMapper(UserTestBatchDOMapper.class);try {for (UserTestBatchDO testBatchDO : testBatchDAOList) {userTestBatchDOMapper.insert(testBatchDO);}//统一提交sqlSession.commit();} catch (Exception e) {//没有提交的数据可以回滚sqlSession.rollback();} finally {//关闭 sqlSessionsqlSession.close();}
}
测试结果
数量 | 耗时 |
---|---|
1000 | 2174ms |
2000 | 3104ms |
3000 | 3801ms |
4000 | 4991ms |
5000 | 5930ms |
8000 | 8151ms |
10000 | 8252ms |
批量修改
1.方式一
批量新增或更新方式
注:需要给唯一主键添加唯一索引,update才会生效
<!-- 批量新增或更新-->
<insert id="batchSaveOrUpdate" parameterType="java.util.List">INSERT INTO lp_user_test_batch(id,user_id,user_name,user_age,type,create_time,update_time)VALUES<foreach collection="list" item="item" index="index" separator=",">(#{item.id,jdbcType=BIGINT},#{item.userId,jdbcType=VARCHAR},#{item.userName,jdbcType=VARCHAR},#{item.userAge,jdbcType=INTEGER},#{item.type,jdbcType=INTEGER},#{item.createTime,jdbcType=TIMESTAMP},#{item.updateTime,jdbcType=TIMESTAMP})</foreach>ON DUPLICATE KEY UPDATEuser_name = VALUES(user_name),user_age = VALUES(user_age),type = VALUES(type),update_time = VALUES(update_time)
</insert>
测试结果
注:当前表内数据行数 10000
数量 | 耗时 |
---|---|
1000 | 1505ms |
2000 | 2617ms |
3000 | 2922ms |
4000 | 3292ms |
5000 | 3443ms |
8000 | 4832ms |
10000 | 4886ms |
优点:速度快
缺点:使用特殊语法 on duplicate key update 语法 增加sql难度性
2.方式二
单条sql+批量方式的SqlSession
<update id="updateByUserId" >UPDATE lp_user_test_batchSETuser_name = #{userName,jdbcType=VARCHAR},user_age = #{userAge,jdbcType=INTEGER},type = #{type,jdbcType=INTEGER},update_time = #{updateTime,jdbcType=TIMESTAMP}WHERE user_id = #{userId,jdbcType=VARCHAR}
</update>
@Resource(name = "sqlSessionFactory")
private SqlSessionFactory sqlSessionFactory;/*** 利用 MyBatis 批处理特性,批量更新*/
public void batchUpdate(List<UserTestBatchDO> testBatchDAOList) {//集合非空if (CollectionUtils.isEmpty(testBatchDAOList)) {return;}//批处理方式 SqlSessionSqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);//获得对应的MapperUserTestBatchDOMapper userTestBatchDOMapper = sqlSession.getMapper(UserTestBatchDOMapper.class);try {for (UserTestBatchDO testBatchDO : testBatchDAOList) {userTestBatchDOMapper.updateByUserId(testBatchDO);}//统一提交sqlSession.commit();//清理缓存,防止溢出sqlSession.clearCache();} catch (Exception e) {//没有提交的数据可以回滚sqlSession.rollback();} finally {//关闭 sqlSessionsqlSession.close();}
}
测试结果
注:当前表内数据行数 10000
数量 | 耗时 |
---|---|
1000 | 3158ms |
2000 | 4324ms |
3000 | 6466ms |
4000 | 7572ms |
5000 | 9812ms |
8000 | 12846ms |
10000 | 16088ms |
优点:通过日志观察,生成一条执行语句sql ,多行参数,统一commit
缺点:比方式一速度略慢
3.方式三
java程序循环调用单条修改语句
执行方式:一条sql ,程序循环执行
for (UserTestBatchDO userTestBatch : testBatchDAOList) {userTestBatchDOMapper.updateByUserId(userTestBatch);
}
测试结果
注:当前表内数据行数 10000
数量 | 耗时 |
---|---|
1000 | 33907ms |
2000 | 42866ms |
3000 | 89675ms |
5000 | 104833ms |
优点:方便单条控制提交事物
缺点:耗时,耗性能、每一次循环都需要与数据库交互一次
4.方式四
Mybatis foreach 循环
执行方式:拼接好一条sql,后执行
<!-- 接收list参数,循环着组装sql语句,注意for循环的写法separator=";" 代表着每次循环完,在sql后面放一个分号 -->
<update id="updateForeachByUserId" parameterType="java.util.List"><foreach collection="list" item="item" separator=";">UPDATE lp_user_test_batchSETuser_name = #{item.userName,jdbcType=VARCHAR},user_age = #{item.userAge,jdbcType=INTEGER},type = #{item.type,jdbcType=INTEGER},update_time = #{item.updateTime,jdbcType=TIMESTAMP}WHERE user_id = #{item.userId,jdbcType=VARCHAR}</foreach>
</update>
测试结果
注:当前表内数据行数 10000
数量 | 耗时 |
---|---|
1000 | 2671ms |
2000 | 4170ms |
3000 | 4514ms |
4000 | 5152ms |
5000 | 6572ms |
8000 | 10209ms |
10000 | 12158ms |
优点:生成多条sql,统一执行,与数据库交互次数少
缺点 : 生成多条拼接的update语句,update语句比较多,量大了就有可能造成sql阻塞。
5.方式五
mybatis sql 使用 case when
<!-- 批量更新第二种方法,通过 case when语句变相的进行批量更新 --><update id="updateCaseByUserId" parameterType="java.util.List">update lp_user_test_batch<trim prefix="set" suffixOverrides=","><!-- 拼接case when 这是另一种写法 --><trim prefix="user_name =case" suffix="end,"><foreach collection="list" item="item"><if test="item.userName!=null">when user_id = #{item.userId,jdbcType=VARCHAR} then #{item.userName,jdbcType=VARCHAR}</if></foreach></trim><trim prefix="user_age =case" suffix="end,"><foreach collection="list" item="item"><if test="item.userAge!=null">when user_id = #{item.userId,jdbcType=VARCHAR} then #{item.userAge,jdbcType=INTEGER}</if></foreach></trim><trim prefix="type =case" suffix="end,"><foreach collection="list" item="item"><if test="item.type!=null">when user_id = #{item.userId,jdbcType=VARCHAR} then #{item.type,jdbcType=INTEGER}</if></foreach></trim><trim prefix="update_time =case" suffix="end,"><foreach collection="list" item="item"><if test="item.type!=null">when user_id = #{item.userId,jdbcType=VARCHAR} then #{item.updateTime,jdbcType=TIMESTAMP}</if></foreach></trim></trim><where>user_id in<foreach collection="list" index="index" item="item" separator="," open="(" close=")">#{item.userId,jdbcType=VARCHAR}</foreach></where></update>
测试结果
注:当前表内数据行数 10000
数量 | 耗时 |
---|---|
1000 | 3201ms |
2000 | 4804ms |
3000 | 6833ms |
4000 | 8554ms |
5000 | 11688ms |
8000 | 26501ms |
10000 | 34724ms |
缺点:
xml中的循环体有点多,每一个case when 都要循环一遍list集合,所以大批量拼sql的时候会比较慢。
生成多条拼接sql,sql长度过长,容易sql超长引起报错 Packet for query is too large。
MySQL 最大允许的 packet
Mybatis批处理介绍
Mybatis内置执行器类型ExecutorType有3种
分别是
ExecutorType.SIMPLE: 不做特殊处理,为每个语句的执行创建一个新的预处理语句。
ExecutorType.REUSE: 可以复用预处理语句。
ExecutorType.BATCH:可以批量执行所有更新语句
SIMPLE与BATCH(批量)对比
默认的是simple,该模式下它为每个语句的执行创建一个新的预处理语句,单条提交sql;
而batch模式重复使用已经预处理的语句,并且批量执行所有更新语句,显然batch性能将更优;但是批量模式无法返回自增主键
测试环境配置
系统:win 8.1
Mysql : 5.7
java环境:junit
注:环境不同可能会引起耗时存在差异。
总结
单次批量操作不要过大,批量新增使用方式一,批量更新方式一与方式二经过测试是最优的选择
也可以根据安全方面综合考虑,选择适合的方式。
关注程序员小强公众号更多编程趣事,知识心得与您分享
Mybatis 批量操作8种实现总结相关推荐
- Destoon数据库配置文件在哪_Mybatis 系列 2:Mybatis 的两种配置文件
Mybatis 的配置文件,有两种: 一.Mybatis 全局配置文件(主配置文件): 起名:不固定,但一般起名要见名知意 --> mybatis-config.xml 路径:classpath ...
- mybatis的2种缓存机制(1)
mybatis的2种缓存机制:一级缓存(SqlSession 级别) 在实际开发中,为了提高数据库的查询速度,我们会用到缓存,而mybatis本身也提供了2种缓存机制来查询缓存来缓存数据,从而达到提高 ...
- Mybatis 批量操作总结
批量新增 1.方式一(常用) <!-- 批量新增--> <insert id="batchSave" parameterType="java.util. ...
- java 数据库 流式查询_关于mybatis:强大MyBatis-三种流式查询方法
基本概念 流式查问指的是查问胜利后不是返回一个汇合而是返回一个迭代器,利用每次从迭代器取一条查问后果.流式查问的益处是可能升高内存应用. [腾讯云]云产品限时秒杀,爆款1核2G云服务器,首年99元 如 ...
- 关于整合spring+mybatis 第三种方式-使用注解
使用注解 1.与前两种方法一致.不过稍许不同的是beans.xml中配置的差异. <!-- 配置sqlSessionFactory --><bean id="sqlSess ...
- springboot 多数据源mybatis的两种整合方法
转载自 springboot-mybatis多数据源的两种整合方法 简介: 随着并发量的不断增加,显然单个数据库已经承受不了高并发带来的压力.一个项目使用多个数据库(无论是主从复制- - 读写分离还 ...
- Mybatis的四种分页方式详解
LIMIT关键字 mapper代码 <select id="selectByPageInfo" resultMap="BaseResult">sel ...
- MyBatis批量操作和多参数查询
批量操作 1.批量添加元素session.insert(String string,Object o) [plain] view plaincopy public void batchInsertSt ...
- Mybatis的5种分页方式
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapperPUBLIC "-/ ...
最新文章
- 2021年大数据常用语言Scala(三十七):scala高级用法 高阶函数用法
- 每日一淘完成1.3亿美元融资,元生资本、DCM领投,SIG联合投资
- linux定时任务案例,Linux定时任务案例
- Yii2 中cookie的用法(2)
- python网络爬虫系列(七)——selenium的介绍 selenium定位获取标签对象并提取数据 selenium的其它使用方法
- C语言课后习题(2)
- 解决 html5 input type='number' 类型可以输入e
- 如何在form初始化时自动隐藏FOLDER列
- [转]飞秋使用说明与常见问题解决方法
- PMP考试备考指南基础知识
- c语言写按键程序,单片机按键设定软件c语言 单片机C语言按键开关程序
- 根据IP获取国家代码
- SQL Server 升序和降序排列
- 港股相关交易规则与业务知识
- 依据Right-BICEP要求的对四则运算2的测试
- nes游戏开发_NES Classic运行Linux,新的0 AD alpha,以及更多游戏新闻
- 论文翻译3-视频流SR技术分析
- mysqldump 备份详解
- 华为ENSP模拟器 AR启动 报错40
- php在线投稿审稿系统,化学试剂在线投稿审稿系统