【Spring】【Mybatis】【事务】Spring + MyBaits + 事务 三者是如何协调的呢?

发布时间 2023-11-28 18:13:16作者: 酷酷-

1  前言

我们知道 Spring 中有数据源、事务,Mybatis 里也有数据源,数据源可以理解为就是数据库连接 Connection,而 Spring中的事务设置的隔离级别、自动提交什么的,其实就是给当前的数据库连接设置的,那么 Mybatis 又是如何巧妙的拿到这个连接并执行相关的语句的呢?我们就来捋捋。

我这里拿 Mybatis-Plus 的代码进行示例哈。

2  事务增强过程溯源

这里不会详细的说代理的对象如何产生的,代理如何执行什么的哈,可以看我之前的代理文章以及AOP哈,我们本章主要看看组件与组件的协调。

我们先来看下事务开启后,怎么拿到数据库连接,怎么设置事务的过程。事务的起点是哪里呢?我们没必要死记,知道SpringBoot的自动装配,那么它的 spring.factories里就有一个关于事务的自动装配,也就是把关于事务的增强引进来:

我拿个示例 debug 来带大家看下事务是一步步拿到数据库连接并且设置连接的事务属性的哈。

首先我这里有一个简单的根据 id 查询的接口:

当然我调接口的时候,会先走进代理增强的哈,也就是会到 invoke里哈,会先走下边这里:

我们继续进入 invokeWithinTransaction 方法:

我们继续进入 createTransactionIfNecessary 方法,改方法里会借助事务管理器 getTransaction,获取事务对象:

我们继续跟进去,里边有一个 startTransaction,即事务开始:

接着进入 doBegin 方法,重点来了,从数据源中获取连接,并设置连接的自动提交为false:

这里可以看到放进了一个 ThreadLocal 对象里,也就是线程的上下文里,这里问下自己,上下文里放的是什么? 是不是一个map对象,那么key是什么呢?是不是我们的数据源对象呢?val是什么呢?是不是我们的数据库连接?是的吧。这里没看明白的话就自己debug下哈,这很重要。

看到这里其实就可以哈,我们画个图捋一下:

关于事务的我们就看到这里哈,细节就不展开了哈,我们主要看协调过程,看下 Mybatis 如何拿到这个连接的呢?接下来我们看看。

3  Mybatis 获取连接

我们先看看 Mybatis 执行的一个过程哈,下边是我看 Mybatis 源码过程中,调试的一个例子,我们看看:

执行大概分四步:

  • 构建 SqlSessionFactory 对象
  • 从SqlSessionFactory 中获取会话SqlSession,其实里边也会获取连接
  • 从会话中获取我们的接口代理类
  • 执行我们的方法,获取结果

那我们从 SqlSessionFactory 的 openSession 看起:

 

事务对象是从事务工厂中获取的那么这里的事务工厂是如何创建的我们看看:

事务工厂又是由环境变量对象来决定的。那要看环境变量的由来,就得看看 Mybatis 结合 Spring 是如何创建的,我这里拿 Mybatis-plus包来说哈,还是自动装配类作为入口。我们看到 MybatisSqlSessionFactoryBean,看名字就是用来构建 SqlSessionFactory 对象交给Spring 管理的哈,细节就不多说了哈。

看这里设置的环境变量,事务工厂是不是 Spring管理的事务工厂。

然后我们 Mybatis 执行的时候,创建事务对象对象是不是就来到了 SpringManagedTransaction:

再来看看获取连接:

可以看到是从 DataSourceUtils 来获取连接,参数就是我们的数据源对象:

我们看看工具类获取连接的过程:

至此,是不是就拿到了我们的连接了,大家自己可以调试一下,看看上边 Spring事务放置的连接对象地址跟这里 Mybatis获取的连接对象是不是一样的哈。

一样我们还是画个图来捋一下:

一个是创建过程:

一个是实际获取连接过程:

4  小结

本节主要看了下事务、spring以及Mybatis的一个协同哈,多思考多调试,有理解不对的地方欢迎指正哈。