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 通过 TransactionFactory(org.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(面向切面编程) 实现声明式事务管理,核心流程如下:
- 当方法被
@Transactional注解修饰时,Spring 会在方法执行前创建事务(通过PlatformTransactionManager.begin())。 - MyBatis 的
SqlSession在事务上下文中获取数据库连接,并绑定到当前线程(通过ThreadLocal)。 - 方法执行完成后,Spring 根据执行结果决定提交(
PlatformTransactionManager.commit())或回滚(PlatformTransactionManager.rollback())事务。
2. MyBatis 与 Spring 的集成点
MyBatis 与 Spring 集成的关键是 SqlSessionTemplate(org.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 的事务控制
JdbcTransaction 的 commit() 方法直接调用 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 深度参与事务管理,具体表现为:
- 独立使用时:通过
JdbcTransaction或ManagedTransaction直接管理 JDBC 事务,用户需显式调用commit()/rollback()。 - 与Spring集成时:事务由 Spring 的
PlatformTransactionManager统一管理,MyBatis 通过SqlSessionTemplate与 Spring 事务上下文同步,用户通过@Transactional声明式控制事务。
无论是哪种模式,MyBatis 的核心目标都是 确保数据库连接与事务的生命周期一致,避免因连接管理不当导致的事务问题(如脏读、幻读)。
浙公网安备 33010602011771号