MybatisPlus实现真正批量插入

在实际开发中,批量插入是提高数据处理效率的常用手段。MyBatis-Plus 作为 MyBatis 的增强工具,提供了多种方式来实现批量插入。然而,默认的 saveBatch 方法在底层实际上是逐条插入,性能上并不理想。本文将详细介绍如何通过 MyBatis-Plus 实现真正高效的批量插入,包括手动拼接 SQL、使用 IService 接口以及自定义 insertBatchSomeColumn 方法,并提供性能优化建议。

文章目录

    • 一、通过 XML 手动拼接 SQL 实现批量插入
      • 优势
      • 缺点
      • 实现步骤
    • 二、使用 MyBatis-Plus `IService` 接口的 `saveBatch` 方法
      • 优势
      • 缺点
      • 提升性能的方法
    • 三、`insertBatchSomeColumn` 方法实现批量插入
      • 优势
      • 实现步骤
        • 1. 自定义SQL注入器实现DefaultSqlInjector,添加InsertBatchSomeColumn方法
        • 2. 将MySqlInjector注入到Bean中
        • 3. 继承Mybatis-plus的BaseMapper,添加插入方法
      • 注意事项
    • 四、性能优化建议
      • 1. 开启批量重写功能
      • 2. 合理设置批量大小
      • 3. 使用事务管理
      • 4. 索引优化
      • 5. 禁用自动提交
    • 参考

一、通过 XML 手动拼接 SQL 实现批量插入

优势

  • 高效:一次性执行批量插入,减少数据库交互次数。
  • 灵活:可以根据需要选择性插入部分字段,减少不必要的数据传输。

缺点

  • 维护成本高:每个表都需要手动编写对应的 XML SQL。
  • 不支持自动生成主键:如果表中有自增主键,需额外处理。

实现步骤

  1. 编写 Mapper XML 文件

    history_summary 表为例,编写批量插入的 XML:

    <insert id="insertBatch" parameterType="java.util.List">INSERT INTO history_summary(key_id, business_no, status, customer_id, instruction_id, customer_business_no, dept_id, doc_type_id, doc_page_no, document_version, result_mongo_doc_id, is_active, problem_status, tran_source, document_count_page, is_rush, is_deleted, document_tran_time, customer_tran_time, preprocess_recv_time, delete_time, create_time, complete_time, version, zip_name, document_no, new_task_type, handle_begin_time, handle_end_time, cost_seconds, char_num, ocr_result_mongo_id, reserve_text2, reserve_text3, reserve_text1, reserve_text4, reserve_text5, ocr_result_type, repeat_status, form_version, repetition_count)VALUES<foreach collection="list" item="item" separator=",">(#{item.keyId}, #{item.businessNo}, #{item.status}, #{item.customerId}, #{item.instructionId}, #{item.customerBusinessNo}, #{item.deptId}, #{item.docTypeId}, #{item.docPageNo}, #{item.documentVersion}, #{item.resultMongoDocId}, #{item.isActive}, #{item.problemStatus}, #{item.tranSource}, #{item.documentCountPage}, #{item.isRush}, #{item.isDeleted}, #{item.documentTranTime}, #{item.customerTranTime}, #{item.preprocessRecvTime}, #{item.deleteTime}, #{item.createTime}, #{item.completeTime}, #{item.version}, #{item.zipName}, #{item.documentNo}, #{item.newTaskType}, #{item.handleBeginTime}, #{item.handleEndTime}, #{item.costSeconds}, #{item.charNum}, #{item.ocrResultMongoId}, #{item.reserveText2}, #{item.reserveText3}, #{item.reserveText1}, #{item.reserveText4}, #{item.reserveText5}, #{item.ocrResultType}, #{item.repeatStatus}, #{item.formVersion}, #{item.repetitionCount})</foreach>
    </insert>
    
  2. 在 Mapper 接口中定义批量插入方法

    public interface historySummaryMapper extends BaseMapper<historySummary> {@Insert({"<script>","INSERT INTO history_summary ","(key_id, business_no, status, customer_id, instruction_id, customer_business_no, dept_id, doc_type_id, doc_page_no, document_version, result_mongo_doc_id, is_active, problem_status, tran_source, document_count_page, is_rush, is_deleted, document_tran_time, customer_tran_time, preprocess_recv_time, delete_time, create_time, complete_time, version, zip_name, document_no, new_task_type, handle_begin_time, handle_end_time, cost_seconds, char_num, ocr_result_mongo_id, reserve_text2, reserve_text3, reserve_text1, reserve_text4, reserve_text5, ocr_result_type, repeat_status, form_version, repetition_count)","VALUES ","<foreach collection='list' item='item' index='index' separator=','>","(#{item.keyId}, #{item.businessNo}, #{item.status}, #{item.customerId}, #{item.instructionId}, #{item.customerBusinessNo}, #{item.deptId}, #{item.docTypeId}, #{item.docPageNo}, #{item.documentVersion}, #{item.resultMongoDocId}, #{item.isActive}, #{item.problemStatus}, #{item.tranSource}, #{item.documentCountPage}, #{item.isRush}, #{item.isDeleted}, #{item.documentTranTime}, #{item.customerTranTime}, #{item.preprocessRecvTime}, #{item.deleteTime}, #{item.createTime}, #{item.completeTime}, #{item.version}, #{item.zipName}, #{item.documentNo}, #{item.newTaskType}, #{item.handleBeginTime}, #{item.handleEndTime}, #{item.costSeconds}, #{item.charNum}, #{item.ocrResultMongoId}, #{item.reserveText2}, #{item.reserveText3}, #{item.reserveText1}, #{item.reserveText4}, #{item.reserveText5}, #{item.ocrResultType}, #{item.repeatStatus}, #{item.formVersion}, #{item.repetitionCount})","</foreach>","</script>"})int insertBatch(@Param("list") List<historySummary> list);
    }
    
  3. 在 Service 层调用批量插入方法

    @Service
    public class historySummaryServiceImpl extends ServiceImpl<historySummaryMapper, historySummary> implements IhistorySummaryService {@Autowiredprivate historySummaryMapper mapper;@Transactional(rollbackFor = Exception.class)public boolean batchInsert(List<historySummary> list) {int result = mapper.insertBatch(list);return result > 0;}
    }
    
  4. 使用示例

    @RestController
    @RequestMapping("/api/business")
    public class BusinessController {@Autowiredprivate IhistorySummaryService service;@PostMapping("/batchInsert")public ResponseEntity<String> batchInsert(@RequestBody List<historySummary> list) {boolean success = service.batchInsert(list);if (success) {return ResponseEntity.ok("批量插入成功");} else {return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("批量插入失败");}}
    }
    

看到这里应该头皮发麻了吧。这也是我为什么想分享这篇文章的原因!!!

涉及到多字段批量插入,还是推荐下面的方法。

二、使用 MyBatis-Plus IService 接口的 saveBatch 方法

MyBatis-Plus 提供的 saveBatch 方法简化了批量插入的操作,但其底层实际上是逐条插入,因此在处理大量数据时性能不佳。

优势

  • 简便易用:无需手动编写 SQL,直接调用接口方法即可。
  • 自动事务管理:内置事务支持,确保数据一致性。

缺点

  • 性能有限:底层逐条插入,面对大数据量时效率较低。
  • 批量大小受限:默认批量大小可能不适用于所有场景,需要手动调整。

提升性能的方法

  1. 配置数据库连接参数

    在数据库的连接 URL 中添加 rewriteBatchedStatements=true,启用批量重写功能,提升批量插入性能。

    spring.datasource.url=jdbc:mysql://localhost:3306/your_database?rewriteBatchedStatements=true
    
  2. 调整批量大小

    在调用 saveBatch 方法时,合理设置批量大小(如 1000 条一批),以平衡性能和资源消耗。

    @Transactional(rollbackFor = {Exception.class})
    public boolean saveBatch(Collection<T> entityList, int batchSize) {String sqlStatement = this.getSqlStatement(SqlMethod.INSERT_ONE);return this.executeBatch(entityList, batchSize, (sqlSession, entity) -> {sqlSession.insert(sqlStatement, entity);});
    }
    

三、insertBatchSomeColumn 方法实现批量插入

为了实现真正高效的批量插入,可以使用 insertBatchSomeColumn 方法,实现一次性批量插入。

优势

  • 高效:一次性执行批量插入,减少数据库交互次数。
  • 灵活:可选择性插入部分字段,优化数据传输。(通过实体类属性)

实现步骤

1. 自定义SQL注入器实现DefaultSqlInjector,添加InsertBatchSomeColumn方法
public class MySqlInjector extends DefaultSqlInjector {@Overridepublic List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);methodList.add(new InsertBatchSomeColumn(i -> i.getFieldFill() != FieldFill.UPDATE));return methodList;}
}
2. 将MySqlInjector注入到Bean中
@Configuration
public class MyBatisConfig {@Beanpublic MySqlInjector sqlInjector() {return new MySqlInjector();}@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor(){MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();//添加分页插件interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//添加乐观锁插件interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());return interceptor;}
}
3. 继承Mybatis-plus的BaseMapper,添加插入方法
public interface MyBaseMapper<T> extends BaseMapper<T> {int insertBatchSomeColumn(Collection<T> entityList);
}
@Mapper
public interface WorkingBusinessHistoryMapper extends MyBaseMapper<BusinessHistory> {
}

注意事项

  • 批量大小:根据数据库和应用的性能,合理设置批量插入的大小,避免单次插入过多数据导致内存溢出或数据库压力过大。
  • 事务管理:确保批量操作在事务中执行,以保证数据的一致性和完整性。
  • 错误处理:在批量操作中,如果某条记录插入失败,需要有相应的机制进行回滚或记录失败信息。

四、性能优化建议

为了进一步提升批量插入的性能,可以采取以下优化措施:

1. 开启批量重写功能

在数据库的连接 URL 中添加 rewriteBatchedStatements=true,以优化批量插入的性能。

spring.datasource.url=jdbc:mysql://localhost:3306/your_database?rewriteBatchedStatements=true

2. 合理设置批量大小

根据具体业务场景和数据库性能,调整批量大小(如 1000 条一批),避免单次插入过多数据。

int batchSize = 1000;
for (int i = 0; i < list.size(); i += batchSize) {List<historySummary> batchList = list.subList(i, Math.min(i + batchSize, list.size()));mapper.insertBatchSomeColumn(batchList);
}

3. 使用事务管理

确保批量操作在事务中执行,避免部分插入成功导致数据不一致。

@Transactional(rollbackFor = Exception.class)
public boolean batchInsert(List<historySummary> list) {int result = mapper.insertBatchSomeColumn(list);return result > 0;
}

4. 索引优化

对插入频繁的表,合理设计索引,避免过多不必要的索引影响插入性能。尽量减少在批量插入时的索引数量,插入完成后再创建必要的索引。

5. 禁用自动提交

在批量插入过程中,禁用自动提交,减少事务提交的次数,提高性能。

jdbcTemplate.execute((ConnectionCallback<Void>) connection -> {connection.setAutoCommit(false);// 执行批量插入操作connection.commit();return null;
});

参考

  • MybatisPlus自定义insertBatchSomeColumn实现真正批量插入 - CSDN博客
  • MybatisPlus如何实现insertBatchSomeColumn进行批量增加 - 亿速云
  • MyBatis-Plus 官方文档
  • MySQL Connector/J Documentation

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/442468.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

5.k8s:helm包管理器,prometheus监控,elk,k8s可视化

目录 一、Helm 包管理器 1.什么是 Helm 2.安装Helm &#xff08;3&#xff09;Helm常用命令 &#xff08;4&#xff09;目录结构 &#xff08;5&#xff09;使用Helm完成redis主从搭建 二、Prometheus集群监控 1.监控方案 2.Prometheus监控k8s 三、ELK日志搜集 1.el…

图片压缩30KB以下怎么做?建议试试这些方法

图片怎么压缩30KB以下&#xff1f;在数字时代&#xff0c;无论是网页设计、社交媒体分享还是电子邮件附件发送&#xff0c;图片的大小往往成为影响加载速度和用户体验的关键因素之一。特别是在需要上传图片到对文件大小有限制的平台时&#xff0c;如何有效地将图片压缩至30KB甚…

【多重循环在Java中的应用】

多重循环在Java中的应用 介绍 多重循环是将一个循环嵌套在另一个循环体内的编程结构。Java中的 for、while 和 do...while 循环均可作为外层循环和内层循环。建议使用两层嵌套&#xff0c;最多不超过三层&#xff0c;以保持代码的可读性。 在多重循环中&#xff0c;外层循环执…

【重学 MySQL】六十二、非空约束的使用

【重学 MySQL】六十二、非空约束的使用 定义目的关键字特点作用创建非空约束删除非空约束注意事项 在MySQL中&#xff0c;非空约束&#xff08;NOT NULL Constraint&#xff09;是一种用于确保表中某列不允许为空值的数据库约束。 定义 非空约束&#xff08;NOT NULL Constra…

ES postman操作全量修改,局部修改,删除

全量修改 修改需要调用的url 地址是http://192.168.1.108:9200/shopping/_doc/1001&#xff0c;调用方法使用put 只修改指定的需求的内容的请求方式 post方式就是局部修改 http://192.168.1.108:9200/shopping/_update/1001&#xff0c;请求方式post 上图是只修改id 为1001数…

Leetcode—416. 分割等和子集【中等】

2024每日刷题&#xff08;172&#xff09; Leetcode—416. 分割等和子集 C实现代码 class Solution { public:bool canPartition(vector<int>& nums) {int sum accumulate(nums.begin(), nums.end(), 0);if(sum % 2) {return false;}int m nums.size();int subSu…

leetcode68:文本左右对齐

给定一个单词数组 words 和一个长度 maxWidth &#xff0c;重新排版单词&#xff0c;使其成为每行恰好有 maxWidth 个字符&#xff0c;且左右两端对齐的文本。 你应该使用 “贪心算法” 来放置给定的单词&#xff1b;也就是说&#xff0c;尽可能多地往每行中放置单词。必要时可…

如何免费为域名申请一个企业邮箱

背景 做SEO的是有老是会有一些网站来做验证你的所有权&#xff0c;这个时候&#xff0c;如果你域名对应的企业邮箱就会很方便。zoho为了引导付费&#xff0c;有很多多余的步骤引导&#xff0c;反倒是让不付费的用户有些迷茫&#xff0c;所以会写这个教程&#xff0c;按照教程走…

2-116 基于matlab的主成分分析(PCA)及累积总和(CUSUM)算法故障监测

基于matlab的主成分分析&#xff08;PCA&#xff09;及累积总和&#xff08;CUSUM&#xff09;算法故障监测&#xff0c;针对传统的多元统计分析方法对生产过程中微小故障检测不灵敏的问题&#xff0c;使用基于主元分析的累积和的微小故障检测方法进行故障监测&#xff0c;通过…

栈与队列面试题(Java数据结构)

前言&#xff1a; 这里举两个典型的例子&#xff0c;实际上该类型的面试题是不确定的&#xff01; 用栈实现队列&#xff1a; 232. 用栈实现队列 - 力扣&#xff08;LeetCode&#xff09; 方法一&#xff1a;双栈 思路 将一个栈当作输入栈&#xff0c;用于压入 push 传入的数…

路由器的工作机制

在一个家庭或者一个公司中 路由器的作用主要有两个(①路由–决定了数据包从来源到目的地的路径 通过映射表决定 ②转送–通过路由器知道了映射表 就可以将数据包从路由器的输入端转移给合适的输出端) 我们可以画一张图来分析一下&#xff1a; 我们好好来解析一下这张图&#x…

胤娲科技:AI重塑会议——灵动未来,会议新纪元

你是否曾经历过这样的会议场景&#xff1a;会议纪要不准确&#xff0c;人名张冠李戴&#xff1b;错过会议&#xff0c;却无从回顾关键内容&#xff1b;会议效率低下&#xff0c;时间白白流逝&#xff1f; 这些问题仿佛成了现代会议的“顽疾”。然而&#xff0c;随着AI技术的飞速…

Pywinauto,一款 Win 自动化利器!

1.安装 pywinauto是一个用于自动化Python模块&#xff0c;适合Windows系统的软件&#xff08;GUI&#xff09;&#xff0c;可以通过Pywinauto遍历窗口&#xff08;对话框&#xff09;和窗口里的控件&#xff0c;也可以控制鼠标和键盘输入&#xff0c;所以它能做的事情比之前介…

论文速读:基于渐进式转移的无监督域自适应舰船检测

这篇文章的标题是《Unsupervised Domain Adaptation Based on Progressive Transfer for Ship Detection: From Optical to SAR Images》基于渐进式转移的无监督域自适应舰船检测:从光学图像到SAR图像&#xff0c;作者是Yu Shi等人。文章发表在IEEE Transactions on Geoscience…

ARTS Week 43

Algorithm 本周的算法题为 1822. 数组元素积的符号 已知函数 signFunc(x) 将会根据 x 的正负返回特定值&#xff1a; 如果 x 是正数&#xff0c;返回 1 。 如果 x 是负数&#xff0c;返回 -1 。 如果 x 是等于 0 &#xff0c;返回 0 。 给你一个整数数组 nums 。令 product 为数…

《神经网络》—— 循环神经网络RNN(Recurrent Neural Network)

文章目录 一、RNN 简单介绍二、RNN 基本结构1.隐藏中的计算2.输出层的计算3.循环 三、RNN 优缺点1.优点2.缺点 一、RNN 简单介绍 循环神经网络&#xff08;Recurrent Neural Network, RNN&#xff09;是一种用于处理序列数据的神经网络架构。 与传统的前馈神经网络&#xff08…

现代身份和访问管理 IAM 如何降低风险

您的公司是否仍在使用 1998 年时的身份管理系统&#xff1f;仅凭用户名和密码就能登录本地网络并访问几乎所有资源吗&#xff1f; 虽然大多数企业已经转向现代身份和访问管理(IAM) 平台&#xff0c;但成千上万的企业和其他组织仍然依赖过时的用户名/密码系统。 如果你看一下传…

微知-如何临时设置Linux系统时间?(date -s “2024-10-08 22:55:00“, time, hwclock, timedatectl)

背景 在tar解压包的时候经常出现时间不对&#xff0c;可以临时用date命令修改一下&#xff0c;也可以其他&#xff0c;本文主要介绍临时修改的方法 date命令修改 sudo date -s "2024-10-08 22:55:00"其他查看和修改的命令 本文只记录查看方式&#xff0c;修改的暂…

分享几个国外SSL证书提供商网站

国外SSL证书提供商 众所周知兼容性高的SSL证书肯定是在国外申请的&#xff0c;主要确保SSL证书的安全性的同时&#xff0c;对于安全标准在国外相比而言更成熟&#xff0c;保护程度也比较高。 另方面对需要申请的域名没有限制&#xff0c;可选性SSL证书类型种类比较多&#xf…

【C++打怪之路Lv7】-- 模板初阶

&#x1f308; 个人主页&#xff1a;白子寰 &#x1f525; 分类专栏&#xff1a;C打怪之路&#xff0c;python从入门到精通&#xff0c;数据结构&#xff0c;C语言&#xff0c;C语言题集&#x1f448; 希望得到您的订阅和支持~ &#x1f4a1; 坚持创作博文(平均质量分82)&#…