如何在 Spring Boot 项目中使用 MyBatis 进行批量操作以提升性能?
MyBatis 提供了 ExecutorType.BATCH 类型,允许将多个 SQL 语句进行组合,最后统一执行,从而减少数据库的访问频率,提升性能。
以下是如何在 Spring Boot 项目中使用 MyBatis 进行批量操作的关键点:
1. 配置 MyBatis 使用 ExecutorType.BATCH
主要有两种方式可以来配置 MyBatis 使用 BATCH 执行器类型:
a) 在 SqlSessionFactoryBean 中配置 (推荐在 Spring Boot 中使用):
在 Spring Boot 应用中,通常通过 SqlSessionFactoryBean 来配置 SqlSessionFactory。我们可以在 SqlSessionFactoryBean 中设置 defaultExecutorType 属性为 BATCH。
import org.apache.ibatis.session.ExecutorType;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import javax.sql.DataSource;@Configuration
public class MyBatisConfig {@Beanpublic SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) throws Exception {SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();factoryBean.setDataSource(dataSource);// 设置默认的 ExecutorType 为 BATCHorg.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();configuration.setDefaultExecutorType(ExecutorType.BATCH);factoryBean.setConfiguration(configuration);// ... 其他配置,例如 Mapper 扫描路径等return factoryBean;}
}
b) 编程式的方式创建 SqlSession 时指定 ExecutorType.BATCH:
如果需要更细粒度的控制,或者只想在特定的操作中使用批量处理,可以在创建 SqlSession 时指定 ExecutorType.BATCH。
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import java.util.List;@Service
public class UserService {@Autowiredprivate SqlSessionFactory sqlSessionFactory;@Autowiredprivate UserMapper userMapper;@Transactionalpublic void batchInsertUsers(List<User> users) {try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) {UserMapper batchMapper = sqlSession.getMapper(UserMapper.class);for (User user : users) {batchMapper.insertUser(user); // 执行插入操作}sqlSession.flushStatements(); // 刷新批处理语句,执行批量操作sqlSession.commit(); // 提交事务}}
}
2. 在 Mapper XML 文件中编写批量操作 SQL
在 Mapper XML 文件中,需要编写能够处理集合参数的 SQL 语句,通常使用 <foreach> 标签来循环遍历集合并构建批量 SQL。
a) 批量 INSERT 示例:
假设有一个 User 实体类,你需要批量插入多个用户。
<!-- UserMapper.xml -->
<mapper namespace="com.example.mapper.UserMapper"><insert id="batchInsertUsers" parameterType="java.util.List" useGeneratedKeys="true" keyProperty="id">insert into users (username, password, email) values<foreach collection="list" item="item" separator=",">(#{item.username}, #{item.password}, #{item.email})</foreach></insert><insert id="insertUser" parameterType="com.example.entity.User" useGeneratedKeys="true" keyProperty="id">insert into users (username, password, email) values (#{username}, #{password}, #{email})</insert><!-- ... 其他 Mapper 方法 --></mapper>
parameterType="java.util.List": 指定方法参数类型为List。<foreach collection="list" item="item" separator="," >: 循环遍历传入的List,item代表当前循环的元素,separator指定元素之间的分隔符为逗号,。(#{item.username}, #{item.password}, #{item.email}): 使用#{item.propertyName}获取User对象的属性值。useGeneratedKeys="true" keyProperty="id": 如果需要获取自增主键,需要配置useGeneratedKeys和keyProperty。
b) 批量 UPDATE 示例:
批量更新多个用户的邮箱地址。
<!-- UserMapper.xml -->
<mapper namespace="com.example.mapper.UserMapper"><update id="batchUpdateUsersEmail" parameterType="java.util.List"><foreach collection="list" item="item" separator=";" open="" close=";" index="index">update users set email = #{item.email} where id = #{item.id}</foreach></update><!-- ... 其他 Mapper 方法 --></mapper>
<foreach collection="list" item="item" separator=";" open="" close=";" index="index">: 循环遍历List,separator=";"使用分号作为分隔符。注意: 这里使用了分号;分隔多个UPDATE语句。不同的数据库对批量 UPDATE 的语法支持可能有所不同,有些数据库可能不支持这种方式,或者有其他更高效的批量更新语法。例如 MySQL 可以使用INSERT ... ON DUPLICATE KEY UPDATE或REPLACE INTO等。
3. Spring Boot Service 层调用批量操作 Mapper 方法
在 Spring Boot Service 层,需要调用 Mapper 接口中定义的批量操作方法,并传入包含数据的 List。务必使用 @Transactional 注解来管理事务,确保批量操作的原子性。
import com.example.entity.User;
import com.example.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import java.util.List;@Service
public class UserService {@Autowiredprivate UserMapper userMapper;@Transactionalpublic void batchInsertUsers(List<User> users) {userMapper.batchInsertUsers(users);}@Transactionalpublic void batchUpdateUsersEmail(List<User> users) {userMapper.batchUpdateUsersEmail(users);}
}
4. 性能优化的关注点
-
事务管理 (
@Transactional): 批量操作必须在事务中进行,以保证操作的原子性。如果批量操作过程中出现错误,可以回滚所有操作,保持数据一致性。Spring Boot 的@Transactional注解可以方便地管理事务。 -
批量大小 (Batch Size): 批量操作并非批量越大越好。过大的批量可能会导致:
- 数据库压力过大: 单次请求发送大量 SQL 可能导致数据库服务器资源消耗过高。
- 内存占用过高: 如果批量操作涉及到大量数据,可能会占用大量内存。
- 事务时间过长: 过长的事务会增加锁冲突的风险,影响并发性能。
最佳批量大小需要根据实际场景进行测试和调优。一般来说,可以尝试从较小的批量大小开始(例如 100, 500, 1000),逐步增加并监控数据库性能,找到最佳的平衡点。
-
数据库连接池配置: 确保数据库连接池配置合理,能够支持高并发的批量操作。Spring Boot 默认使用 HikariCP 连接池,性能良好,但仍需根据应用负载调整连接池参数,例如
maximum-pool-size,minimum-idle等。 -
网络延迟: 批量操作的主要优势是减少网络 round trips。如果网络延迟较高,批量操作的性能提升会更加明显。
-
数据库服务器性能: 最终性能也受限于数据库服务器的性能。确保数据库服务器配置合理,性能良好,例如 CPU, 内存, 磁盘 IO 等。
-
批量操作的适用场景: 批量操作最适合一次性处理大量数据的场景,例如数据导入、数据迁移、批量更新状态等。对于频繁的小批量操作,可能提升效果不明显,甚至可能因为额外的批处理开销而降低性能。
-
Generated Keys 的处理: 如果批量 INSERT 需要获取自增主键,MyBatis 提供了
useGeneratedKeys和keyProperty属性。但需要注意,不同数据库对批量获取自增主键的支持程度可能有所不同。对于 MySQL,批量 INSERT 可以一次性获取所有自增主键。 -
错误处理: 批量操作中如果某条 SQL 执行失败,需要妥善处理错误。默认情况下,MyBatis 的
ExecutorType.BATCH在遇到错误时会停止执行后续的 SQL。我们需要根据业务需求,决定是忽略错误继续执行,还是回滚整个批量操作。
总结:
在 Spring Boot 项目中使用 MyBatis 的 ExecutorType.BATCH 进行批量操作,可以显著提升处理大量数据的性能。关键在于正确配置 ExecutorType.BATCH,编写高效的批量 SQL 语句,合理设置批量大小,并结合事务管理和错误处理机制。 性能优化是一个迭代过程,需要根据实际应用场景和性能测试结果进行调整和完善。
相关文章:
如何在 Spring Boot 项目中使用 MyBatis 进行批量操作以提升性能?
MyBatis 提供了 ExecutorType.BATCH 类型,允许将多个 SQL 语句进行组合,最后统一执行,从而减少数据库的访问频率,提升性能。 以下是如何在 Spring Boot 项目中使用 MyBatis 进行批量操作的关键点: 1. 配置 MyBatis 使…...
基于SSM的线上花店鲜花销售商城网站系统
作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏:…...
Python Lambda表达式详解
Python Lambda表达式详解 1. Lambda是什么? Lambda是Python中用于创建匿名函数(没有名字的函数)的关键字,核心特点是简洁。它适用于需要临时定义简单函数的场景,或直接作为参数传递给高阶函数(如map()、f…...
DAPP实战篇:使用web3.js连接合约
说明 本系列内容目录:专栏:区块链入门到放弃查看目录 如果你还没有创建好项目请先查看:《DApp实战篇:先用前端起个项目》,如果你还不知道web3.js是什么请先查看:《DApp实战篇:前端技术栈一览》。 安装 点此查看web3.js官方文档 打开项目根目录,并唤起终端: 键入w…...
linux sar 系统运行状态统计
概述 sar 命令来自英文词组**“System activity reporter”**的缩写,其功能是用于统计系统运行状态。是一个系统活动报告工具,用于收集、报告和保存系统活动信息。它可以帮助系统管理员监控和分析系统性能,识别潜在的性能瓶颈或问题。 实时…...
【C#】一种优雅的基于winform的串口通信管理
serialPort.DataReceived、串口优雅管理 完整《C#串口通信系统》功能清单 Part 1 — SerialPortManager.cs —— 串口核心管理类 using System; using System.IO.Ports; using System.Text; using System.Threading; using System.Windows.Forms;/// <summary> /// 专业…...
ChatGPT之智能驾驶问题讨论
ChatGPT之智能驾驶问题讨论 1. 源由2. 问题:2.1 智能驾驶级别定义🚗 L2(部分自动化,Partial Automation)🤖 L3(有条件自动化,Conditional Automation)🛸 L4&a…...
K8S-证书过期更新
K8S证书过期问题 K8S证书过期处理方法 Unable to connect to the server: x509: certificate has expired or is not yet valid 1、查看证书有效期: # kubeadm certs check-expiration2、备份证书 # cp -rp /etc/kubernetes /etc/kubernetes.bak3、直接重建证书 …...
蓝桥杯第十五届真题——握手问题
#include<bits/stdc.h> using namespace std; int main() {ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);int sum0;for(int i7;i<49;i){sumi;}cout<<sum;return 0; }...
5G_WiFi_CE_DFS
目录 一、规范要求 1、法规目录 2、定义 3、运行模式 4、主/从设备相关的运行行为及具体的动态频率选择(DFS)要求 5、产品角色确定测试项目 6、测试项目 测试项1:信道可用性检查(Channel Availability Check) …...
第二节:React 基础篇-受控组件 vs 非受控组件
一、场景题:设计一个实时搜索输入框,说明选择依据 受控组件 vs 非受控组件 核心区别 特征受控组件非受控组件数据管理由React状态(state)控制通过DOM元素(ref)直接访问更新时机每次输入触发onChange提交…...
springboot 处理编码的格式为opus的音频数据解决方案【java8】
opus编码的格式概念: Opus是一个有损声音编码的格式,由Xiph.Org基金会开发,之后由IETF(互联网工程任务组)进行标准化,目标是希望用单一格式包含声音和语音,取代Speex和Vorbis,且适用…...
RK3568 基于Gstreamer的多媒体调试记录
文章目录 1、环境介绍2、概念理清3、提前准备4、GStreamer编译5、GStreamer基础介绍6、视频播放初体验7、视频硬编码7.1、h2647.2、h265 8、视频硬解码8.1、解码视频并播放8.2、解码视频并播放带音频 1、环境介绍 硬件:飞凌ok3568-c开发板 软件:原厂rk…...
VS Code 的 .S 汇编文件里面的注释不显示绿色
1. 确认文件语言模式 打开 .S 文件后,查看 VS Code 右下角的状态栏,确认当前文件的识别模式(如 Assembly、Plain Text 等)。如果显示为 Plain Text 或其他非汇编模式: 点击状态栏中的语言模式(如 Plain Te…...
在 Wireshark 中如何筛选数据包
1. 显示过滤器(Display Filters) 显示过滤器用于 在已捕获的数据包中筛选,语法类似于编程语言中的条件表达式。 (1)基本过滤 表达式说明ip.addr 192.168.1.1显示所有涉及 192.168.1.1 的 IP 包ip.src 192.168.1.1…...
[MySQL]数据库与表创建
欢迎来到啾啾的博客🐱。 这是一个致力于构建完善 Java 程序员知识体系的博客📚。 它记录学习点滴,分享工作思考和实用技巧,偶尔也分享一些杂谈💬。 欢迎评论交流,感谢您的阅读😄。 本篇简单记录…...
5分钟读懂ArgoCD:在Kubernetes中实现持续部署
Kubernetes中的Argo CD介绍 Argo CD是用于Kubernetes的声明式GitOps持续交付工具。它遵循GitOps模式,以Git仓库作为定义所需应用程序状态的唯一真实来源,能在指定的目标环境中自动部署应用程序,并持续监控应用程序的运行状态,确保…...
cs224w课程学习笔记-第10课
cs224w课程学习笔记-第10课 异构图 前言一、异构图1、异构图定义2、异构图与同构图 二、异构图下的GNN1、GCN扩展至RGCN1.1 RGCN原理1.2 异构图的任务预测特点1.3 异构图任务预测基础案例 2、完整的异构图GCN三、异构图下的Transformer 前言 异构图的定义是节点内部存在类型不…...
OpenCV 图形API(26)图像滤波-----方框滤波函数boxFilter()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 使用方框滤波器模糊图像。 该函数使用以下内核来平滑图像: K α [ 1 1 … 1 1 1 … 1 ⋮ ⋮ ⋱ ⋮ 1 1 … 1 ] K \alpha \begin{b…...
安卓手机怎样开启双WiFi加速
1. 小米/Redmi手机 路径: 设置 → WLAN → 高级设置 → 双WLAN加速 操作: 开启功能后,可同时连接一个2.4GHz WiFi和一个5GHz WiFi(或两个不同路由器)。 可选择“智能选择”或手动指定辅助网络。 2. 华为/荣耀手机…...
大模型上下文协议MCP详解(2)—核心功能
版权声明 本文原创作者:谷哥的小弟作者博客地址:http://blog.csdn.net/lfdfhl1. 标准化上下文交互技术 1.1 实时数据接入能力 MCP(Model Context Protocol)通过标准化的接口,为 AI 模型提供了强大的实时数据接入能力,使其能够快速获取和处理来自不同数据源的实时信息。…...
剑指Offer(数据结构与算法面试题精讲)C++版——day8
剑指Offer(数据结构与算法面试题精讲)C版——day8 题目一:链表中环的入口节点题目二:两个链表的第1个重合节点题目三:反转链表附录:源码gitee仓库 题目一:链表中环的入口节点 这道题的有如下三个…...
【Qt】QxOrm:下载、安装、使用
1、下载源码 github地址:https://github.com/QxOrm/QxOrm 稳定版本下载:https://github.com/QxOrm/QxOrm/releases/tag/1.5.0 2、编译源码 QxOrm支持cmake编译(CMakeLists.txt)、Qt pro工程编译(QxOrm.pro) 以 QxOrm.pro 为例,编译生成的库,没有在 build-QxOrm-1.5…...
CISCO组建RIP V2路由网络
1.实验准备: 2.具体配置: 2.1根据分配好的IP地址配置静态IP: 2.1.1PC配置: PC0: PC1: PC2: 2.1.2路由器配置: R0: Router>en Router#conf t Enter configuration…...
【数学建模】(智能优化算法)鲸鱼优化算法(Whale Optimization Algorithm)详解与应用
鲸鱼优化算法(Whale Optimization Algorithm)详解与应用 文章目录 鲸鱼优化算法(Whale Optimization Algorithm)详解与应用1. 引言2. 算法原理2.1 生物学基础2.2 数学模型[^3]1. 包围猎物阶段2. 气泡网攻击(螺旋更新)3. 随机搜索猎物(全局探索…...
【深度洞察】解码饮料行业破局点:场景革命
当东鹏特饮以 “大瓶装 防尘盖” 精准解决货车司机的场景化需求,当农夫山泉通过 “冷藏版东方树叶” 打开年轻白领的早餐场景 —— 这些现象级案例背后,是饮料行业底层逻辑的深刻变革:真正的市场增量,藏在对消费场景的极致拆解中…...
工业科学级天文相机:跨界融合的高精密成像解决方案
随着国内科技的快速发展,工业相机领域正悄然兴起一场"天文级"的技术革命。这类兼具工业设备可靠性与天文观测精度的特殊相机,正在半导体制造、天文观测、空间探测等领域开辟新的应用疆域。其核心技术突破不仅体现在传感器性能的提升࿰…...
回文日期2
#include <bits/stdc.h> using namespace std; bool huiwen(int date) {int tempdate;int r0;while(temp>0){rr*10temp%10;temp/10;}return dater; }int main() {// 请在此输入您的代码int n,m;cin>>n>>m;int tempfn/100,tempem/100;int yearfn/10000,mon…...
Ubuntu搭建Pytorch环境
Ubuntu搭建Pytorch环境 例如:第一章 Python 机器学习入门之pandas的使用 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 Ubuntu搭建Pytorch环境前言一、Anaconda二、Cuda1.安装流程2、环境变量&#…...
图书管理系统(Python)
运行结果: 源代码: # 定义一个图书类 class Book: def __init__(self, title, author, isbn): self.title title self.author author self.isbn isbn def show_info(self): print(f"{self.title},{self.author},{self.isbn}") # 图书列表…...
