mybatis中的事务操作

MyBatis 会深度参与事务的相关操作,其事务管理机制可分为 独立使用场景(直接管理JDBC事务)和 与Spring集成场景(依赖Spring事务管理器)两种模式。以下结合源码和实际使用场景详细说明:

一、独立使用MyBatis时的事务管理

在未与Spring集成的独立项目中,MyBatis 通过内置的 Transaction 接口及其实现类直接管理数据库事务,核心逻辑围绕 JDBC连接的事务控制 展开。

1. 事务管理的核心组件:Transaction 接口

MyBatis 定义了 Transaction 接口(org.apache.ibatis.transaction.Transaction),负责事务的 开启、提交、回滚连接管理。其核心方法如下:

public interface Transaction {
  Connection getConnection() throws SQLException; // 获取数据库连接
  void commit() throws SQLException; // 提交事务
  void rollback() throws SQLException; // 回滚事务
  void close() throws SQLException; // 关闭连接
}

2. Transaction 的具体实现类

MyBatis 提供了两种内置的 Transaction 实现:

(1)JdbcTransaction(JDBC事务管理器)
  • 核心逻辑:直接使用 JDBC 的 Connection 对象管理事务。
  • 关键行为
    • 事务的 commit()rollback() 直接调用 Connection.commit()Connection.rollback()
    • 连接的自动提交(autoCommit)状态由 MyBatis 控制:默认情况下,MyBatis 会将连接的 autoCommit 设为 false(开启事务),直到显式调用 commit()rollback() 后才会恢复。
(2)ManagedTransaction(容器托管事务管理器)
  • 核心逻辑:将事务管理委托给外部容器(如应用服务器或Spring),自身不主动提交或回滚事务。
  • 适用场景:在应用服务器(如JBoss、WebLogic)中使用时,由容器负责事务的生命周期管理(如通过JTA)。

3. 事务的创建与配置

MyBatis 通过 TransactionFactoryorg.apache.ibatis.transaction.TransactionFactory)创建 Transaction 实例,其类型由 mybatis-config.xml 中的 <transactionManager> 标签配置:

<!-- mybatis-config.xml -->
<environments default="development">
  <environment id="development">
    <transactionManager type="JDBC"/> <!-- 或 MANAGED -->
    <dataSource type="POOLED">
      <!-- 数据源配置 -->
    </dataSource>
  </environment>
</environments>
  • type="JDBC" 时,使用 JdbcTransactionFactory 创建 JdbcTransaction
  • type="MANAGED" 时,使用 ManagedTransactionFactory 创建 ManagedTransaction

4. 独立使用时的事务操作示例

在独立项目中,用户需通过 SqlSession 显式管理事务:

SqlSession sqlSession = sqlSessionFactory.openSession(); // 默认不自动提交(autoCommit=false)
try {
  UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
  userMapper.insertUser(new User("张三"));
  userMapper.updateUserStatus(1L, "ACTIVE");
  sqlSession.commit(); // 显式提交事务
} catch (Exception e) {
  sqlSession.rollback(); // 异常时回滚
} finally {
  sqlSession.close();
}

二、与Spring集成时的事务管理

当 MyBatis 与 Spring 集成时,事务管理由 Spring 的 PlatformTransactionManager 接管,MyBatis 仅负责 连接的生命周期管理,并与 Spring 事务上下文同步。

1. Spring 事务的核心机制

Spring 通过 AOP(面向切面编程) 实现声明式事务管理,核心流程如下:

  1. 当方法被 @Transactional 注解修饰时,Spring 会在方法执行前创建事务(通过 PlatformTransactionManager.begin())。
  2. MyBatis 的 SqlSession 在事务上下文中获取数据库连接,并绑定到当前线程(通过 ThreadLocal)。
  3. 方法执行完成后,Spring 根据执行结果决定提交(PlatformTransactionManager.commit())或回滚(PlatformTransactionManager.rollback())事务。

2. MyBatis 与 Spring 的集成点

MyBatis 与 Spring 集成的关键是 SqlSessionTemplateorg.mybatis.spring.SqlSessionTemplate),它是 SqlSession 的代理类,负责:

  • 在 Spring 事务上下文中获取 SqlSession(通过 SqlSessionFactory)。
  • 确保 SqlSession 使用的连接与当前事务的连接一致(通过 TransactionSynchronizationManager 绑定)。

3. 集成后的事务操作示例

在 Spring 项目中,用户通过 @Transactional 声明式管理事务,无需显式调用 commit()rollback()

@Service
public class UserService {
  @Autowired
  private UserMapper userMapper;

  @Transactional // Spring 自动管理事务
  public void updateUser(Long userId, String newName) {
    User user = userMapper.selectById(userId);
    user.setName(newName);
    userMapper.update(user);
    // 若方法内抛出异常(如运行时异常),Spring 自动回滚事务
  }
}

三、MyBatis 事务管理的源码关键逻辑

MyBatis 事务管理的底层实现可通过以下源码细节进一步理解:

1. JdbcTransaction 的事务控制

JdbcTransactioncommit() 方法直接调用 JDBC 连接的 commit()

// JdbcTransaction.java
public void commit() throws SQLException {
  if (connection != null && !connection.isClosed()) {
    if (!autoCommit) {
      connection.commit(); // 提交事务
    }
  }
}

2. SqlSessionTemplate 与 Spring 事务的绑定

SqlSessionTemplate 通过 SqlSessionInterceptor(内部类)拦截所有 SqlSession 方法调用,确保使用与 Spring 事务绑定的连接:

// SqlSessionTemplate.java
private class SqlSessionInterceptor implements InvocationHandler {
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    SqlSession sqlSession = getSqlSession(
        SqlSessionTemplate.this.sqlSessionFactory,
        SqlSessionTemplate.this.executorType,
        SqlSessionTemplate.this.exceptionTranslator); // 从 Spring 事务上下文获取 SqlSession
    try {
      Object result = method.invoke(sqlSession, args); // 调用实际 SqlSession 方法
      if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
        sqlSession.commit(true); // 非事务场景自动提交(如未使用 @Transactional)
      }
      return result;
    } catch (Throwable t) {
      // 异常处理...
    } finally {
      closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory); // 释放 SqlSession
    }
  }
}

3. 事务连接的获取与绑定(Spring 场景)

Spring 的 DataSourceTransactionManager 在事务开始时会从数据源获取连接,并通过 TransactionSynchronizationManager 绑定到当前线程:

// DataSourceTransactionManager.java
protected void doBegin(Object transaction, TransactionDefinition definition) {
  DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
  Connection con = DataSourceUtils.getConnection(obtainDataSource()); // 获取连接
  txObject.setConnectionHolder(new ConnectionHolder(con), true);
  con.setAutoCommit(false); // 关闭自动提交,开启事务
  TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder()); // 绑定到线程
}

四、总结

MyBatis 深度参与事务管理,具体表现为:

  • 独立使用时:通过 JdbcTransactionManagedTransaction 直接管理 JDBC 事务,用户需显式调用 commit()/rollback()
  • 与Spring集成时:事务由 Spring 的 PlatformTransactionManager 统一管理,MyBatis 通过 SqlSessionTemplate 与 Spring 事务上下文同步,用户通过 @Transactional 声明式控制事务。

无论是哪种模式,MyBatis 的核心目标都是 确保数据库连接与事务的生命周期一致,避免因连接管理不当导致的事务问题(如脏读、幻读)。

posted on 2025-05-26 12:23  斜月三星一太阳  阅读(279)  评论(0)    收藏  举报