从源码看 MyBatis-Plus 与 Spring 的 DataSourceTransactionManager 有没有直接关联?


从源码看 MyBatis-Plus 与 Spring 的 DataSourceTransactionManager 有没有直接关联?

MyBatis-Plus(简称 MP)的事务管理用起来挺顺手,但它到底跟 Spring 的 DataSourceTransactionManager 有没有直接关系?这个问题得从源码里找答案。今天咱们就来扒一扒 MP 和 Spring 的源码,看看它们是怎么配合的,MP 是不是直接跟 DataSourceTransactionManager 杠上了。

1. 先说结论

先剧透一下:MyBatis-Plus 本身跟 DataSourceTransactionManager 没有直接关联 。MP 的事务管理完全依赖 Spring 的基础设施,核心是 Spring 的 @Transactional 注解和 DataSourceTransactionManager。MP 只是个"借力打力"的角色,负责执行 SQL,而事务的控制权在 Spring 手里。

下面咱们一步步从源码里挖证据。

2. Spring 的事务管理:DataSourceTransactionManager

Spring 的事务管理核心是 PlatformTransactionManager 接口,DataSourceTransactionManager 是它的一个实现类,专门管 JDBC 数据源的事务。咱们先看看它咋工作的。

2.1 DataSourceTransactionManager 的核心逻辑

DataSourceTransactionManager 的源码在 doBegindoCommitdoRollback 方法里:

java 复制代码
// org.springframework.jdbc.datasource.DataSourceTransactionManager
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
    Connection con = null;
    try {
        // 获取数据库连接
        con = obtainDataSource().getConnection();
        txObject.setConnectionHolder(new ConnectionHolder(con), true);
        // 设置手动提交
        con.setAutoCommit(false);
        // 设置隔离级别、超时等
        prepareConnectionForTransaction(con, definition);
    } catch (SQLException ex) {
        // 处理异常
    }
}

@Override
protected void doCommit(DefaultTransactionStatus status) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
    Connection con = txObject.getConnectionHolder().getConnection();
    try {
        con.commit(); // 提交事务
    } catch (SQLException ex) {
        throw new TransactionSystemException("Could not commit JDBC transaction", ex);
    }
}

@Override
protected void doRollback(DefaultTransactionStatus status) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
    Connection con = txObject.getConnectionHolder().getConnection();
    try {
        con.rollback(); // 回滚事务
    } catch (SQLException ex) {
        throw new TransactionSystemException("Could not roll back JDBC transaction", ex);
    }
}

这几段代码干了啥? - doBegin:拿到数据源的 Connection,关掉自动提交,开始事务。 - doCommit:提交事务,把操作写到数据库。 - doRollback:回滚事务,撤销操作。

这些操作都是针对 JDBC 的 Connection,跟具体的 ORM 框架没直接关系。

2.2 Spring 的事务拦截

Spring 用 AOP 拦截带 @Transactional 的方法,核心类是 TransactionInterceptor。它的 invoke 方法会调用 TransactionManager

java 复制代码
// org.springframework.transaction.interceptor.TransactionInterceptor
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
    TransactionAttributeSource tas = getTransactionAttributeSource();
    TransactionAttribute txAttr = tas.getTransactionAttribute(invocation.getMethod(), targetClass);
    PlatformTransactionManager tm = determineTransactionManager(txAttr);
    // 创建事务状态
    TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
    Object retVal;
    try {
        // 执行目标方法
        retVal = invocation.proceed();
    } catch (Throwable ex) {
        // 出错了就回滚
        completeTransactionAfterThrowing(txInfo, ex);
        throw ex;
    }
    // 正常结束就提交
    commitTransactionAfterReturning(txInfo);
    return retVal;
}

这里 tm 就是 DataSourceTransactionManager,它负责事务的开启、提交和回滚。

3. MyBatis-Plus 的角色

MP 的事务管理完全靠 Spring,它自己没实现任何事务逻辑。MP 的核心是 SqlSessionMapper,这些都跟 MyBatis 一样,走的是 JDBC 的路子。咱们看看 MP 的源码。

3.1 MP 的 SqlSession

MP 用的是 MyBatis 的 SqlSession,通过 SqlSessionFactory 创建。在 Spring 环境下,SqlSession 是由 SqlSessionTemplate 代理的:

java 复制代码
// org.mybatis.spring.SqlSessionTemplate
public class SqlSessionTemplate implements SqlSession {
    private final SqlSessionFactory sqlSessionFactory;
    private final ExecutorType executorType;
    private final SqlSession sqlSessionProxy;

    public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        this(sqlSessionFactory, ExecutorType.SIMPLE);
    }

    @Override
    public <T> T selectOne(String statement, Object parameter) {
        return this.sqlSessionProxy.selectOne(statement, parameter);
    }
}

SqlSessionTemplate 的构造方法会从 Spring 的 DataSource 获取连接,而这个连接已经被 DataSourceTransactionManager 控制了事务状态(比如 autoCommit=false)。

3.2 MP 的 BaseMapper

MP 的 BaseMapper 是通用 CRUD 的核心,比如 insert 方法:

java 复制代码
// com.baomidou.mybatisplus.core.mapper.BaseMapper
@InsertProvider(type = SqlProviderAdapter.class, method = "insert")
int insert(T entity);

这个方法最终会调用 MyBatis 的 SqlSession.insert,而 SqlSession 的连接是从 Spring 的事务上下文里拿的。源码里没见到 MP 自己去碰 DataSourceTransactionManager,它只管发 SQL。

4. 两者怎么配合?

从源码看,MP 和 DataSourceTransactionManager 的关系是间接的,中间靠 Spring 搭桥: 1. 你在 Service 方法上加 @Transactional,Spring 的 TransactionInterceptor 拦截。 2. DataSourceTransactionManager 开启事务,控制 Connection。 3. MP 的 Mapper 通过 SqlSession 执行 SQL,用的是同一个 Connection。 4. 方法结束,Spring 根据执行结果提交或回滚。

MP 本身不直接调用 DataSourceTransactionManager,甚至不知道它的存在。它只关心 SQL 执行,事务的生命周期全交给 Spring。

5. 代码验证

写个例子,看看实际效果:

java 复制代码
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private OrderMapper orderMapper;

    @Transactional(rollbackOn = Exception.class)
    public void addUserAndOrder(String username, String orderName) {
        User user = new User();
        user.setUsername(username);
        user.setAge(25);
        baseMapper.insert(user);

        Order order = new Order();
        order.setUserId(user.getId());
        order.setOrderName(orderName);
        orderMapper.insert(order);

        throw new RuntimeException("故意出错");
    }
}

@SpringBootTest
class SourceTest {

    @Autowired
    private UserService userService;

    @Test
    void testTransaction() {
        try {
            userService.addUserAndOrder("张三", "手机");
        } catch (Exception e) {
            System.out.println("捕获异常: " + e.getMessage());
        }
    }
}

跑完后,数据库啥也没加。因为 DataSourceTransactionManager 检测到异常,调用了 Connection.rollback(),MP 的两个 insert 都被撤销了。

6. 小结

从源码角度,MyBatis-Plus 跟 DataSourceTransactionManager 没直接关联。MP 只是个 SQL 执行工具,事务管理全靠 Spring 的 @TransactionalDataSourceTransactionManager。MP 的 SqlSession 用的是 Spring 提供的事务性连接,事务的开关都在 Spring 手里。

所以,MP 的事务能力其实是"借来的",它跟 DataSourceTransactionManager 的关系是间接的,通过 Spring 的整合串起来。明白了这个,写代码时只要管好 @Transactional,MP 自然会配合得妥妥的。

有啥想再深挖的没?比如某个具体方法的源码,我可以再展开讲讲!

相关推荐
苏墨瀚1 小时前
SQL语言的散点图
开发语言·后端·golang
一只韩非子6 小时前
一句话告诉你什么叫编程语言自举!
前端·javascript·后端
沈二到不行6 小时前
多头注意力&位置编码:完型填空任务
人工智能·后端·deepseek
追逐时光者6 小时前
C# 中比较实用的关键字,基础高频面试题!
后端·c#·.net
GoGeekBaird7 小时前
一文搞懂:Anthropic发布MCP重要更新,告别长连接
后端·操作系统
Asthenia04127 小时前
面试问题分析:为什么Java能实现反射机制,其他语言不行?
后端
拳布离手7 小时前
fastgpt工作流探索
后端
Asthenia04128 小时前
IO 多路复用详解:从概念->系统调用-> Java 在NIO中实现
后端
Asthenia04128 小时前
场景题-Java 单体项目优化:应对高并发客户端访问的性能与线程安全分析
后端
安然无虞8 小时前
31天Python入门——第5天:循环那些事儿
开发语言·后端·python