对比 MyBatis 批处理 BATCH 模式与 INSERT INTO ... SELECT ... UNION ALL 进行批量插入
前言
在开发中,我们经常需要批量插入大量数据。不同的批量插入方法有不同的优缺点,适用于不同的场景。本文将详细对比两种常见的批量插入方法:
- MyBatis 的批处理模式。
- 使用
INSERT INTO ... SELECT ... UNION ALL
进行批量插入。
MyBatis 批处理模式
实现方式
MyBatis 的批处理模式通过配置 SqlSessionTemplate
或 SqlSessionFactory
的 ExecutorType
为 BATCH
来启用。以下是一个示例配置:
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {return new SqlSessionTemplate(sqlSessionFactory, ExecutorType.BATCH);
}
优点
- 易于实现:只需配置
ExecutorType
即可启用批处理模式。 - 灵活:支持多种类型的 SQL 操作,包括插入、更新和删除,常规标准 SQL 不因数据库差异而使用不同的写法。
- 动态 SQL:支持 MyBatis 的动态 SQL 功能,可以根据条件生成复杂的 SQL 语句。
缺点
- 性能限制:虽然批处理可以减少网络往返次数,提高性能,但对于非常大的数据集,性能方面会有一定的影响。
- 内存占用:批处理过程中需要在内存中累积大量的数据,可能导致内存溢出。
- 数据库支持:批处理的效果取决于数据库驱动的支持程度,某些驱动可能不完全支持批处理。
示例代码
@Autowired
private SqlSessionTemplate sqlSessionTemplate;public void batchInsert(List<Item> items, int batchSize, int commitBatchCount) {try (SqlSession sqlSession = sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH)) {ItemMapper mapper = sqlSession.getMapper(ItemMapper.class);int batchCount = 0;for (int i = 0; i < items.size(); i += batchSize) {int end = Math.min(i + batchSize, items.size());for (int j = i; j < end; j++) {mapper.insert(items.get(j));}sqlSession.flushStatements();batchCount++;if (commitBatchCount != -1 && batchCount % commitBatchCount == 0) {sqlSession.commit();batchCount = 0;}}if (batchCount > 0 || commitBatchCount == -1) {sqlSession.commit();}} catch (Exception e) {// 处理异常e.printStackTrace();}
}
解释
batchSize
:控制每次批处理的条数,即每次调用mapper.insert
方法的次数。commitBatchCount
:控制每执行几次批处理后提交一次事务。如果commitBatchCount
为-1
,则表示在所有数据插入完成后一次性提交事务。flushStatements
:每次处理完一批数据后,手动刷新批处理中的 SQL 语句,确保数据被发送到数据库。commit
:根据commitBatchCount
的值决定何时提交事务。如果commitBatchCount
为-1
,则在所有数据插入完成后一次性提交事务。
使用 INSERT INTO ... SELECT ... UNION ALL
实现方式
使用 INSERT INTO ... SELECT ... UNION ALL
方法可以通过构建一个包含多个 UNION ALL
子句的 SQL 语句来一次性插入多条记录。以下是一个示例:
INSERT INTO table_name (column1, column2)
SELECT 'value1', 'value2'
UNION ALL
SELECT 'value3', 'value4'
UNION ALL
SELECT 'value5', 'value6';
优点
- 高性能:一次性插入多条记录,减少了数据库的 I/O 操作,提高了插入速度。
- 内存友好:不需要在内存中累积大量数据,减少了内存占用。毕竟它只是执行了一条字符串比较长的 SQL 语句而已。
缺点
- 复杂性:生成包含大量
UNION ALL
子句的 SQL 语句可能非常复杂,容易出错。且不同类型的数据库拼接 SQL 的语法可能有差异。 - SQL 限制:SQL 语句长度有限制,如果插入的数据量过大,可能会超过数据库的最大 SQL 长度限制。需要注意当前数据库的最大允许长度。
- 错误处理:一旦插入失败,很难定位具体的错误记录,因为所有的插入操作是在一条 SQL 语句中完成的。
- 灵活性差:只能用于插入操作,不适用于更新或删除操作。
- 动态 SQL 支持差:难以根据条件动态生成 SQL 语句,只适用比较纯粹的 INSERT 语句。
示例代码
MyBatis XML 文件示例
假设我们有一个 Item
对象,包含 column1
和 column2
两个字段。
<!-- src/main/resources/mapper/ItemMapper.xml -->
<mapper namespace="com.example.mapper.ItemMapper"><!-- 插入单个记录的映射 --><insert id="insert" parameterType="com.example.model.Item">INSERT INTO table_name (column1, column2) VALUES (#{column1}, #{column2})</insert><!-- 批量插入记录的映射 --><insert id="batchInsertWithUnionAll" parameterType="java.util.List">INSERT INTO table_name (column1, column2)<foreach collection="list" item="item" separator="UNION ALL">SELECT #{item.column1}, #{item.column2}</foreach></insert></mapper>
Java 方法示例
@Autowired
private SqlSessionTemplate sqlSessionTemplate;public void batchInsertWithUnionAll(List<Item> items) {try (SqlSession sqlSession = sqlSessionTemplate.getSqlSessionFactory().openSession()) {ItemMapper mapper = sqlSession.getMapper(ItemMapper.class);mapper.batchInsertWithUnionAll(items);sqlSession.commit();} catch (Exception e) {// 处理异常e.printStackTrace();}
}
解释
<foreach>
标签:遍历传入的List<Item>
列表,生成多个SELECT
子句,每个子句对应一条记录。separator="UNION ALL"
:指定每个子句之间用UNION ALL
分隔。
性能测试
为了更好地理解这两种方法的性能差异,我们可以进行一些基准测试。以下是一个简单的测试示例:
@Autowired
private SqlSessionTemplate sqlSessionTemplate;@Test
public void testBatchInsertPerformance() {int itemCount = 10000;List<Item> items = generateItems(itemCount);// 测试 MyBatis 批处理模式long startTime = System.currentTimeMillis();batchInsert(items, 1000, 10); // 每10次批处理提交一次事务long endTime = System.currentTimeMillis();System.out.println("MyBatis 批处理模式耗时: " + (endTime - startTime) + " ms");// 清空表数据clearTable();// 测试 INSERT INTO ... SELECT ... UNION ALLstartTime = System.currentTimeMillis();batchInsertWithUnionAll(items);endTime = System.currentTimeMillis();System.out.println("INSERT INTO ... SELECT ... UNION ALL 耗时: " + (endTime - startTime) + " ms");
}private List<Item> generateItems(int count) {List<Item> items = new ArrayList<>(count);for (int i = 0; i < count; i++) {items.add(new Item("value1_" + i, "value2_" + i));}return items;
}private void clearTable() {sqlSessionTemplate.getSqlSessionFactory().openSession().getMapper(ItemMapper.class).truncateTable();
}
解释
generateItems
方法:生成指定数量的Item
对象。clearTable
方法:清空表中的数据,以便进行下一次测试。
总结
选择哪种批量插入方法取决于你的具体需求和应用场景:
- MyBatis 批处理模式:
- 数据量适中:适用于数据量不是特别大,但需要频繁插入、更新或删除的场景。
- 需要灵活的 SQL 操作:需要支持多种类型的 SQL 操作,如插入、更新和删除。
- 需要细粒度的错误处理:需要在批处理完成后检查每个操作的结果,以便发现和处理错误。
INSERT INTO ... SELECT ... UNION ALL
:- 大数据量插入:适用于需要一次性插入大量数据的场景,尤其是数据量非常大时。
- 性能要求高:对插入性能有较高要求,需要尽可能减少数据库的 I/O 操作。
- 简单的插入操作:只涉及插入操作,不需要支持更新或删除。
至此本文主要内容已经结束。
补充
针对单纯 INSERT 的超大数量级场景,可以结合两种方式实现高效插入。你可以先使用 INSERT INTO … SELECT … UNION ALL 构建批量插入的 SQL 语句,然后在适当的时候提交事务。这样既可以利用 UNION ALL 的高性能,又可以通过控制提交频率来避免事务过大导致的问题。
下面是主要代码片段,可以按需选择并使用。
<mapper namespace="com.example.mapper.ItemMapper"><!-- 批量插入记录的映射 --><insert id="batchInsertWithUnionAll" parameterType="java.util.List">INSERT INTO table_name (column1, column2)<foreach collection="list" item="item" separator="UNION ALL">SELECT #{item.column1}, #{item.column2}</foreach></insert>
</mapper>
@Autowired
private SqlSessionTemplate sqlSessionTemplate;public void batchInsertCombined(List<Item> items, int batchSize, int commitBatchCount) {try (SqlSession sqlSession = sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH)) {ItemMapper mapper = sqlSession.getMapper(ItemMapper.class);int batchCount = 0;for (int i = 0; i < items.size(); i += batchSize) {int end = Math.min(i + batchSize, items.size());List<Item> batchItems = items.subList(i, end);mapper.batchInsertWithUnionAll(batchItems);sqlSession.flushStatements();batchCount++;if (commitBatchCount != -1 && batchCount % commitBatchCount == 0) {sqlSession.commit();batchCount = 0;}}if (batchCount > 0 || commitBatchCount == -1) {sqlSession.commit();}} catch (Exception e) {// 处理异常e.printStackTrace();}
}
希望这篇文章对你有所帮助!如果有任何进一步的问题或需要更多细节,请随时告诉我。
相关文章:
对比 MyBatis 批处理 BATCH 模式与 INSERT INTO ... SELECT ... UNION ALL 进行批量插入
前言 在开发中,我们经常需要批量插入大量数据。不同的批量插入方法有不同的优缺点,适用于不同的场景。本文将详细对比两种常见的批量插入方法: MyBatis 的批处理模式。使用 INSERT INTO ... SELECT ... UNION ALL 进行批量插入。 MyBatis …...
AI大模型如何重塑软件开发流程与模式
AI大模型如何重塑软件开发流程与模式 随着人工智能技术的不断发展,AI大模型正在逐步改变软件开发的方式。传统的软件开发流程,尽管经过多年的演进,使得许多企业能够顺利进行软件开发,但仍然面临着许多挑战,例如开发周…...

NUXT3学习日记五(composables、$fetch和useAsyncData、useFetch,lazy,refresh)
composables 在 Nuxt 3 中,composables(组合式函数)是一种用于封装和复用有状态逻辑的机制。它类似于 Vue 3 中的组合式 API,允许你将相关的逻辑(如数据获取、状态管理等)提取到独立的函数中,然…...
MySQL原理简介—10.SQL语句和执行计划
大纲 1.什么是执行计划 2.执行计划包含哪些内容 3.SQL语句和执行计划的总结 4.SQL语句使用多个二级索引 5.多表关联的SQL语句如何执行 6.全表扫描执行计划的成本计算方法 7.索引的成本计算方法 8.MySQL如何优化执行计划 9.explain的参数说明 1.什么是执行计划 (1)什么…...
wordpress二开-WordPress新增页面模板-说说微语
微语说说相当于一个简单的记事本,使用还是比较方便的。这个版本的说说微语CSS样式不兼容,可能有些主题无法适配,但是后台添加内容,前端显示的逻辑已经实现。可以当作Word press二开中自定义页面模板学习~ 一、后台添加说说微语模…...
001 MATLAB介绍
前言: 软件获取渠道有很多,难点也就是百度网盘下载慢; 线上版本每月有时间限制。 01 MATLAB介绍 性质: MATLAB即Matrix Laboratory 矩阵实验室的意思,是功能强大的计算机高级语言, 已广泛应用于各学科研究部门、…...

Linux—进程概念学习-03
目录 Linux—进程学习—31.进程优先级1.1Linux中的进程优先级1.2修改进程优先级—top 2.进程的其他概念3.进程切换4.环境变量4.0环境变量的理解4.1环境变量的基本概念4.2添加环境变量—export4.3Linux中环境变量的由来4.4常见环境变量4.5和环境变量相关的命令4.6通过系统调用获…...

低速接口项目之串口Uart开发(二)——FIFO实现串口数据的收发回环测试
本节目录 一、设计思路 二、loop环回模块 三、仿真模块 四、仿真验证 五、上板验证 六、往期文章链接本节内容 一、设计思路 串口数据的收发回环测试,最简单的硬件测试是把Tx和Rx连接在一起,然后上位机进行发送和接收测试,但是需要考虑到串…...

java: itext8.05 create pdf
只能调用windows 已安装的字体,这样可以在系统中先预装字体,5.0 可以调用自配文件夹的字体文件。CSharp donetItext8.0 可以调用。 /*** encoding: utf-8* 版权所有 2024 ©涂聚文有限公司 言語成了邀功盡責的功臣,還需要行爲每日來值班…...
如何用通义灵码快速绘制流程图?
使用通义灵码快速绘制流程图?新功能体验 不想读前人“骨灰级”代码,不想当“牛马”程序员,想像看图片一样快速读复杂代码和架构? 通义灵码已经支持代码逻辑可视化,可以把你的每段代码画成流程图。像个脑图工具一样帮你…...

vue 预览pdf 【@sunsetglow/vue-pdf-viewer】开箱即用,无需开发
sunsetglow/vue-pdf-viewer 开箱即用的pdf插件sunsetglow/vue-pdf-viewer, vue3 版本 无需多余开发,操作简单,支持大文件 pdf 滚动加载,缩放,左侧导航,下载,页码,打印,文本复制&…...

Java NIO 核心知识总结
在学习 NIO 之前,需要先了解一下计算机 I/O 模型的基础理论知识。还不了解的话,可以参考我写的这篇文章:Java IO 模型详解。 一、NIO 简介 在传统的 Java I/O 模型(BIO)中,I/O 操作是以阻塞的方式进行的。…...

疑难Tips:NextCloud域名访问登录时卡住,显示违反内容安全策略
[ 知识是人生的灯塔,只有不断学习,才能照亮前行的道路 ] 1使用域名访问Nextcloud用户登录时卡住,显示违反内容安全策略 我使用官方Docker镜像来部署NextCloud 28.0.5,并通过Openresty反向代理Nextcloud,但是在安装后无法稳定工作,每次登录后,页面会卡死在登录界面,无法…...

C 语言学习-06【指针】
1、目标单元与简介存取 直接访问和间接访问 #include <stdio.h>int main(void) {int a 3, *p;p &a;printf("a %d, *p %d\n", a, *p);*p 10;printf("a %d, *p %d\n", a, *p);printf("Enter a: ");scanf("%d", &a)…...

如何快速将Excel数据导入到SQL Server数据库
工作中,我们经常需要将Excel数据导入到数据库,但是对于数据库小白来说,这可能并非易事;对于数据库专家来说,这又可能非常繁琐。 这篇文章将介绍如何帮助您快速的将Excel数据导入到sql server数据库。 准备工作 这里&…...

【人工智能】Python在机器学习与人工智能中的应用
Python因其简洁易用、丰富的库支持以及强大的社区,被广泛应用于机器学习与人工智能(AI)领域。本教程通过实用的代码示例和讲解,带你从零开始掌握Python在机器学习与人工智能中的基本用法。 1. 机器学习与AI的Python生态系统 Pyth…...

使用八爪鱼爬虫抓取汽车网站数据,分析舆情数据
我是做汽车行业的,可以用八爪鱼爬虫抓取汽车之家和微博上的汽车文章内容,分析各种电动汽车口碑数据。 之前,我写过很多Python网络爬虫的案例,使用requests、selenium等技术采集数据,这次尝试去采集小米SU7在微博、汽车…...
什么是事务?事务有哪些特性?
在数据库管理中,事务是一个核心概念,它确保了数据操作的完整性和一致性。本文将探讨事务的定义及其四大特性。 一、事务的定义 事务是数据库操作的最小工作单元,是作为单个逻辑工作单元执行的一系列操作。这些操作作为一个整体一起向系统提…...
玩转合宙Luat教程 基础篇④——程序基础(库、线程、定时器和订阅/发布)
文章目录 一、前言二、库三、线程四、定时器五、订阅/发布5.1 回调函数5.2 堵塞等待一、前言 教程目录大纲请查阅:玩转合宙Luat教程——导读 写一写Lua程序基础的东西。 包括如何调用库,如何创建线程、如何创建定时器,如何使用订阅/发布事件。 二、库 程序从main.lua开始通…...

24.<Spring博客系统①(数据库+公共代码+持久层+显示博客列表+博客详情)>
项目整体预览 登录页面 主页 查看全文 编辑 写博客 PS:Service.impl(现在流行写法) 推荐写法。后续完成项目。会尝试这样写。 接口可以有多个实现。每个实现都可以不同。 这也算一种设计模式。叫做(策略模式)。 我们…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...

K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...

跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...

html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

C++:多态机制详解
目录 一. 多态的概念 1.静态多态(编译时多态) 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1).协变 2).析构函数的重写 5.override 和 final关键字 1&#…...

深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...