批量新增

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种实现总结相关推荐

  1. Destoon数据库配置文件在哪_Mybatis 系列 2:Mybatis 的两种配置文件

    Mybatis 的配置文件,有两种: 一.Mybatis 全局配置文件(主配置文件): 起名:不固定,但一般起名要见名知意 --> mybatis-config.xml 路径:classpath ...

  2. mybatis的2种缓存机制(1)

    mybatis的2种缓存机制:一级缓存(SqlSession 级别) 在实际开发中,为了提高数据库的查询速度,我们会用到缓存,而mybatis本身也提供了2种缓存机制来查询缓存来缓存数据,从而达到提高 ...

  3. Mybatis 批量操作总结

    批量新增 1.方式一(常用) <!-- 批量新增--> <insert id="batchSave" parameterType="java.util. ...

  4. java 数据库 流式查询_关于mybatis:强大MyBatis-三种流式查询方法

    基本概念 流式查问指的是查问胜利后不是返回一个汇合而是返回一个迭代器,利用每次从迭代器取一条查问后果.流式查问的益处是可能升高内存应用. [腾讯云]云产品限时秒杀,爆款1核2G云服务器,首年99元 如 ...

  5. 关于整合spring+mybatis 第三种方式-使用注解

    使用注解 1.与前两种方法一致.不过稍许不同的是beans.xml中配置的差异. <!-- 配置sqlSessionFactory --><bean id="sqlSess ...

  6. springboot 多数据源mybatis的两种整合方法

    转载自  springboot-mybatis多数据源的两种整合方法 简介: 随着并发量的不断增加,显然单个数据库已经承受不了高并发带来的压力.一个项目使用多个数据库(无论是主从复制- - 读写分离还 ...

  7. Mybatis的四种分页方式详解

    LIMIT关键字 mapper代码 <select id="selectByPageInfo" resultMap="BaseResult">sel ...

  8. MyBatis批量操作和多参数查询

    批量操作 1.批量添加元素session.insert(String string,Object o) [plain] view plaincopy public void batchInsertSt ...

  9. Mybatis的5种分页方式

    <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapperPUBLIC "-/ ...

最新文章

  1. 2021年大数据常用语言Scala(三十七):scala高级用法 高阶函数用法
  2. 每日一淘完成1.3亿美元融资,元生资本、DCM领投,SIG联合投资
  3. linux定时任务案例,Linux定时任务案例
  4. Yii2 中cookie的用法(2)
  5. python网络爬虫系列(七)——selenium的介绍 selenium定位获取标签对象并提取数据 selenium的其它使用方法
  6. C语言课后习题(2)
  7. 解决 html5 input type='number' 类型可以输入e
  8. 如何在form初始化时自动隐藏FOLDER列
  9. [转]飞秋使用说明与常见问题解决方法
  10. PMP考试备考指南基础知识
  11. c语言写按键程序,单片机按键设定软件c语言 单片机C语言按键开关程序
  12. 根据IP获取国家代码
  13. SQL Server 升序和降序排列
  14. 港股相关交易规则与业务知识
  15. 依据Right-BICEP要求的对四则运算2的测试
  16. nes游戏开发_NES Classic运行Linux,新的0 AD alpha,以及更多游戏新闻
  17. 论文翻译3-视频流SR技术分析
  18. mysqldump 备份详解
  19. 华为ENSP模拟器 AR启动 报错40
  20. php在线投稿审稿系统,化学试剂在线投稿审稿系统

热门文章

  1. 存储市场竞争加剧 美光科技再次光荣绽放
  2. Android培训武汉,武汉安卓培训之Android如何使用样式创建半透明窗体
  3. IT十年人生过客1-开篇
  4. 【深度学习机器翻译】GNMT:Google 的的神经机器翻译系统
  5. 不懂数据库的码农不是好程序员!
  6. 网易企业邮箱:三道防御、七项措施,切实保障企业邮箱安全【企业邮箱申请】
  7. selenium+python模拟浏览器进入好友QQ空间留言
  8. 二级java pdf_全国计算机等级考试二级Java语言程序设计.PDF
  9. 阿里云centos8安装rabbitMq
  10. 记录微机大作业-----流水灯