Mybatis 批处理

275 阅读3分钟

MyBatis 提供了 三种 Executor 执行器,用于执行 SQL 语句和处理结果集。它们是:

  1. SimpleExecutor(默认)
  2. ReuseExecutor
  3. BatchExecutor

🌟 1. SimpleExecutor(默认)

  • 每次执行 SQL 语句时都会创建一个新的 Statement 对象。
  • 执行完成后立即关闭 Statement
  • 不会复用 Statement 对象。

🔸 特点:

✅ 适合简单的、查询频率不高的操作。
✅ 不会占用数据库连接池资源。
❌ 性能较低,频繁创建和销毁 Statement,消耗资源。


示例:使用 SimpleExecutor

SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.SIMPLE);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.getUserById(1);
sqlSession.commit();
sqlSession.close();

👉 每次 mapper.getUserById() 都会创建新的 Statement 对象,执行完毕后立即销毁。


🌟 2. ReuseExecutor

  • 在执行 SQL 语句时,MyBatis 会尝试复用 Statement 对象。
  • 如果 SQL 语句与之前执行的相同,MyBatis 会复用已存在的 Statement,而不是重新创建。

🔸 特点:

✅ 适合执行频率较高的重复查询。
✅ 减少了 Statement 的创建和销毁,性能更高。
❌ 只对完全相同的 SQL 语句起作用(包括参数占位符结构)。


示例:使用 ReuseExecutor

SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.REUSE);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user1 = mapper.getUserById(1);
User user2 = mapper.getUserById(2);
sqlSession.commit();
sqlSession.close();

👉 如果两个 getUserById 生成的 SQL 语句结构相同(即 "SELECT * FROM user WHERE id = ?"),会复用 Statement


🌟 3. BatchExecutor

  • 在执行 SQL 语句时,MyBatis 会将多个 SQL 语句缓存起来,最后一次性批量发送到数据库执行。
  • 适合批量插入、批量更新等场景。

🔸 特点:

✅ 大幅减少与数据库的通信次数,提升性能。
✅ 适合批量操作场景,如导入数据或大批量更新。
❌ 需要手动提交(commit())。
❌ 在批处理失败时,可能会出现部分成功、部分失败的情况,事务处理复杂。


示例:使用 BatchExecutor

SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);

mapper.insertUser(new User(1, "Tom", 20));
mapper.insertUser(new User(2, "Jerry", 22));
mapper.insertUser(new User(3, "Spike", 25));

sqlSession.commit(); // 一次性提交
sqlSession.close();

👉 MyBatis 会将 3 条 INSERT 语句合并为一个批处理操作,最后通过 commit() 一次性发送到数据库。


🔥 执行器之间的区别总结

执行器类型创建 Statement复用 Statement适用场景性能
SimpleExecutor每次执行创建新的 Statement❌ 不复用普通的单次查询和操作🚀🚀
ReuseExecutor相同 SQL 语句复用 Statement✅ 复用相同 SQL 的 Statement高频率执行相同 SQL 的场景🚀🚀🚀
BatchExecutor批量创建和执行 Statement✅ 批量复用批量插入、批量更新🚀🚀🚀🚀

🎯 选择策略

✅ 如果查询或操作非常频繁且重复 → 选择 ReuseExecutor
✅ 如果是批量插入、批量更新等场景 → 选择 BatchExecutor
✅ 如果是普通场景,没有特殊性能要求 → 使用默认的 SimpleExecutor

MyBatis 中如何指定使用哪一种 Executor 执行器

对!这是因为在 MyBatis 中,Executor 的选择是由 MyBatis 框架自动处理的,所以在大多数情况下,你不需要直接在代码中指定 Executor 类型。


🌟 1. MyBatis 的默认行为

在没有明确配置的情况下,MyBatis 默认会使用 SimpleExecutor

👉 默认配置来自于 mybatis-config.xml

<configuration>
    <settings>
        <setting name="defaultExecutorType" value="SIMPLE"/>
    </settings>
</configuration>

defaultExecutorType 取值可以是:

  • SIMPLE → 使用 SimpleExecutor(默认)
  • REUSE → 使用 ReuseExecutor
  • BATCH → 使用 BatchExecutor

🌟 2. 如何在代码中指定 Executor 类型

如果你需要显式指定 Executor 类型,可以通过 SqlSessionFactory.openSession() 方法设置:

🔸 使用 SIMPLE 执行器

SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.SIMPLE);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.getUserById(1);
sqlSession.close();

🔸 使用 REUSE 执行器

SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.REUSE);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user1 = mapper.getUserById(1);
User user2 = mapper.getUserById(2);
sqlSession.close();

🔸 使用 BATCH 执行器

SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.insertUser(new User(1, "Tom", 20));
mapper.insertUser(new User(2, "Jerry", 22));
sqlSession.commit();  // 一次性提交
sqlSession.close();

🌟 3. 如果你用的是 Spring + MyBatis

在 Spring 配置中,也可以通过设置 defaultExecutorType 来配置全局 Executor 类型:

👉 在 application.propertiesapplication.yml 文件中配置:

mybatis.configuration.default-executor-type=REUSE

为什么平时没见过?

  1. 大多数情况下,使用默认的 SIMPLE 执行器已经够用了。
  2. MyBatis 会根据 SQL 类型和场景自动选择合适的执行器。
  3. 直接配置在 mybatis-config.xmlapplication.properties 中,通常无需手动指定。

🚀 只有在性能优化或批量操作场景下,才需要手动指定 Executor! 😎

在spring 中默认是用的simple 如果为某几个单独设置batch 可以用以下方法

SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
try {
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    List<User> users = getUsers(); // 假设该方法返回需要更新的用户列表
    for (User user : users) {
        userMapper.updateStatusById(user.getId(), user.getStatus());
    }
    sqlSession.commit();
} catch (Exception e) {
    sqlSession.rollback();
} finally {
    sqlSession.close();
}