当前位置:首页 > 工具 > 正文内容

MyBatis 批量操作优化:使用 ExecutorType.BATCH 提升数据处理性能

访客 工具 2026年7月5日 1

在基于 MyBatis 或通用 Mapper 进行开发时,处理大规模数据的写入或更新是一个常见需求。许多开发者习惯使用 <foreach> 标签在 XML 中拼接复杂的批量 SQL。然而,当数据量达到一定规模时,拼接出的超长 SQL 不仅会消耗大量内存,还可能超出数据库对单条 SQL 长度的限制。

更为优雅且高效的解决方案是利用 MyBatis 原生提供的 BATCH 执行器。通过 JDBC 的批处理机制,可以显著减少客户端与数据库之间的网络交互次数,从而大幅提升增删改操作的性能。

BATCH 模式代码实现

以下示例展示了如何通过注入 SqlSessionFactory 来开启批处理会话,并对用户积分进行批量更新。代码中引入了批次大小常量,以控制内存中缓存的语句数量。

@Autowired
private SqlSessionFactory sessionFactory;

@Transactional(rollbackFor = Exception.class)
@Override
public void processBatchPointUpdates() {
    // 获取支持批量执行的 SqlSession
    SqlSession batchSession = sessionFactory.openSession(ExecutorType.BATCH);
    UserPointMapper mapper = batchSession.getMapper(UserPointMapper.class);
    
    List<UserPoint> records = mapper.fetchAllActive();
    final int BATCH_CHUNK_SIZE = 100;
    
    for (int i = 0; i < records.size(); i++) {
        UserPoint item = records.get(i);
        item.setBonusPoints(item.getBonusPoints() + 10);
        mapper.updateBonusPoints(item);
        
        // 每处理 100 条数据,向数据库刷新一次批处理语句
        if ((i + 1) % BATCH_CHUNK_SIZE == 0) {
            batchSession.flushStatements();
        }
    }
    // 确保最后不足一个批次的数据也被提交
    batchSession.flushStatements();
}

在上述代码中,核心在于通过 ExecutorType.BATCH 创建 SqlSession。在此会话下获取的 Mapper 接口,其所有的修改操作都会自动进入批处理队列,直到调用 flushStatements() 时才会真正发送给数据库执行。

执行日志分析

开启 DEBUG 级别日志后,可以观察到 BATCH 模式下的 SQL 执行特征。MyBatis 会预编译一次 SQL,随后连续绑定多组参数,直到触发 flushStatements() 或达到 JDBC 驱动的批处理上限时,才会重新进行预编译。

DEBUG ==>  Preparing: UPDATE user_point SET bonus_points = ? WHERE user_id = ?
DEBUG ==> Parameters: 110(Integer), 1001(Long)
DEBUG ==> Parameters: 65(Integer), 1002(Long)
DEBUG ==> Parameters: 88(Integer), 1003(Long)
... (省略中间参数)
DEBUG ==> Parameters: 80(Integer), 1100(Long)
DEBUG ==>  Preparing: UPDATE user_point SET bonus_points = ? WHERE user_id = ?
DEBUG ==> Parameters: 25(Integer), 1101(Long)
DEBUG ==> Parameters: 42(Integer), 1102(Long)
... (省略中间参数)
DEBUG ==> Parameters: 95(Integer), 1200(Long)

关键注意事项

1. Spring 事务接管机制

在 Spring 与 MyBatis 整合的架构中,数据库连接和事务由 SpringManagedTransaction 统一管理。这意味着开发者无需(也不应)手动调用 commit()rollback(),同时也不需要显式调用 close() 来关闭 SqlSession。在 Spring 托管环境下,手动干预事务或关闭会话不仅多余,还可能引发不可预知的异常。

2. SQL 连续性与适用范围

  • 操作类型限制BATCH 执行器仅对 INSERTUPDATEDELETE 操作生效。对于 SELECT 查询,MyBatis 会直接执行而不会将其放入批处理队列。
  • 保持 SQL 连续性:JDBC 批处理要求相同的 SQL 语句连续执行。如果在循环中交替执行不同的 SQL(例如一条 INSERT 紧接一条 UPDATE),MyBatis 会频繁切换底层的 Statement,导致批处理失效,退化为普通的单条执行模式。因此,在编写批量逻辑时,务必对数据进行分组,确保同类型的 SQL 操作集中且连续地执行。
标签: MyBatis

相关文章

Trojan服务器搭建与配置

一、整体架构(先对齐认知)Clash Meta (PC / iOS / Android)        ↓ TLS   Trojan Server (443)        ↓     InternetTrojan 的核心是: TLS + HTTPS 流量伪装 看起来像正常网站 非常适合...

Tailscale 的详细用法

Tailscale 是一种基于 WireGuard 协议 的 零配置 VPN(虚拟私有网络)服务,让设备之间能够 安全、加密地直接连接,就像它们在同一个本地网络一样。它的核心特点是 简单、安全、跨平台。Tailscale 非常适合 没有公网 IP、两台电脑不在同一局域网 的场景。 简单来说,Tailscale 是什么?Tailscale 是一款让你的各种设备(电脑、服务器、手机...

Clash Tun 模式 导致 爱快(iKuai SD-Wan)内网域名无法访问

一、Clash  DNS 配置dns:  enable: true  listen: 0.0.0.0:53  ipv6: true  enhanced-mode: redir-host  nameserver:    - 223.5.5.5    - 223.6.6.6iKuai 内网域名 ...

深入解析Node.js运行环境与异步I/O架构

深入解析Node.js运行环境与异步I/O架构

核心定义与价值Node.js本质上是一个JavaScript运行环境,而非编程语言或应用框架。它赋予了JavaScript脱离浏览器在服务端、命令行工具及网络应用中执行的能力。其核心意义在于:用单一语言打通前后端开发壁垒。基于事件驱动与非阻塞I/O的架构特性,Node.js在处理API网关、实时通信及微服务等I/O密集型场景时表现卓越,已成为现代后端工程的主流选择。浏览器沙箱限制1995年Java...

ADO.NET SQL参数化查询的最佳实践

在 ADO.NET 中执行 SQL 查询时,参数化查询是一种关键的安全措施和性能优化手段。它通过将 SQL 命令和用户提供的数据分开处理,有效防止了 SQL 注入攻击,并有助于数据库缓存执行计划。下面总结了几种常用的参数化查询方式。 1. 使用 SqlParameter 对象(推荐) 这是最推荐的参数化查询方式。通过显式创建 SqlParameter 对象,您可以精确控制参数的类...

基于ELK的日志集中化分析系统搭建

构建统一日志管理平台的必要性 在分布式架构中,各服务节点独立运行,日志分散存储于不同主机。传统通过命令行工具如grep、awk逐个检索日志的方式,在数据量庞大时效率极低,难以实现快速定位问题。为提升运维效率,需建立集中式日志处理体系,具备日志采集、传输、存储、分析与告警能力。 ELK技术栈核心组件解析 Elasticsearch:分布式搜索引擎,支持全文检索、实时数据分析和高可用集群部署,...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。