MyBatis 事务管理

189 阅读3分钟

MyBatis 的事务管理机制是其与数据库交互的核心功能之一,主要通过 事务管理器数据源 来实现对事务的控制。以下从原理和示例两个方面详细解析 MyBatis 的事务管理。


一、事务管理的核心原理

1. 事务管理器类型

MyBatis 支持两种事务管理器:

  • JDBC 基于 JDBC 的 Connection 对象管理事务,需手动调用 commit()rollback()

    <transactionManager type="JDBC"/>
    
  • MANAGED 将事务控制权交给外部容器(如应用服务器),MyBatis 不主动管理事务。

    <transactionManager type="MANAGED"/>
    
2. 事务的生命周期
  • 事务的开启:当创建 SqlSession 时,事务自动开启。
  • 事务的提交:需显式调用 SqlSession.commit()(JDBC 模式)。
  • 事务的回滚:出现异常时调用 SqlSession.rollback(),或依赖容器自动回滚(MANAGED 模式)。
  • 事务的关闭:关闭 SqlSession 时,事务自动结束。
3. 隔离级别与传播行为
  • 隔离级别:通过数据库连接 URL 设置(如 REPEATABLE_READ)。

    jdbc:mysql://localhost:3306/test?transactionIsolation=REPEATABLE_READ
    
  • 传播行为:MyBatis 原生不支持复杂传播行为,但与 Spring 集成后可借助 @Transactional 实现。


二、事务管理的配置与使用示例

1. 原生 JDBC 事务管理

配置示例mybatis-config.xml):

<environments default="development">
  <environment id="development">
    <transactionManager type="JDBC"/>
    <dataSource type="POOLED">
      <property name="driver" value="com.mysql.jdbc.Driver"/>
      <property name="url" value="jdbc:mysql://localhost:3306/test"/>
      <property name="username" value="root"/>
      <property name="password" value="123456"/>
    </dataSource>
  </environment>
</environments>

代码示例:手动提交与回滚事务

SqlSession sqlSession = sqlSessionFactory.openSession(); // 默认不自动提交
try {
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    userMapper.insertUser(user1); // 插入操作
    userMapper.updateUser(user2); // 更新操作
    sqlSession.commit(); // 手动提交事务
} catch (Exception e) {
    sqlSession.rollback(); // 异常时回滚
    e.printStackTrace();
} finally {
    sqlSession.close(); // 关闭会话
}
2. 与 Spring 集成实现声明式事务

配置 Spring 事务管理器

<!-- 配置数据源 -->
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
    <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"/>
    <property name="username" value="root"/>
    <property name="password" value="123456"/>
</bean><!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean><!-- 启用注解驱动的事务管理 -->
<tx:annotation-driven transaction-manager="transactionManager"/>

代码示例:使用 @Transactional 注解

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;
​
    @Transactional(
        propagation = Propagation.REQUIRED, // 默认传播行为
        isolation = Isolation.READ_COMMITTED, // 隔离级别
        rollbackFor = Exception.class // 异常时回滚
    )
    public void updateUserWithLog(User user) {
        userMapper.updateUser(user); // 更新用户
        userMapper.insertLog(user.getId(), "UPDATE"); // 插入日志
        // 若此处抛出异常,事务自动回滚
    }
}
3. 事务隔离级别示例

设置数据库连接的隔离级别为 READ_COMMITTED

jdbc:mysql://localhost:3306/test?transactionIsolation=READ_COMMITTED

三、事务管理的常见问题与解决方案

1. 事务未提交或回滚
  • 原因:未调用 commit()rollback(),或配置了自动提交。
  • 解决:确保在 JDBC 模式下显式提交/回滚,或检查 openSession() 的参数。
2. 长事务导致性能问题
  • 场景:事务持有时间过长,占用数据库连接。
  • 优化:缩短事务范围,避免在事务中执行耗时操作。
3. 死锁问题
  • 场景:多个事务竞争同一资源。
  • 排查:通过数据库日志分析死锁原因,优化 SQL 执行顺序。

四、总结与最佳实践

  • 事务管理器选择

    • JDBC:适合简单场景,需手动控制提交/回滚。
    • MANAGED:适合容器管理环境(如 Java EE 应用服务器)。
    • Spring 集成:推荐使用声明式事务(@Transactional),简化代码。
  • 隔离级别建议

    • 默认使用 READ_COMMITTED,平衡性能与一致性。
    • 高并发场景慎用 SERIALIZABLE,避免性能瓶颈。
  • 最佳实践

    1. 在 Service 层统一管理事务。
    2. 避免在事务中执行远程调用或复杂计算。
    3. 结合连接池配置(如 HikariCP)优化并发性能。

通过合理配置和使用事务,可以显著提升 MyBatis 应用的数据一致性和可靠性。