## 目录
![](https://itsoku.oss-cn-hangzhou.aliyuncs.com/itsoku/blog/article/129/1b732bf9-5059-4687-8a17-c2e719ce72cd.png)
## 环境
1. jdk1.8
2. Spring版本:5.2.3.RELEASE
3. mysql5.7
## 回顾一下编程式事务用法
```java
@Test
public void test1() throws Exception {
//定义一个数据源
org.apache.tomcat.jdbc.pool.DataSource dataSource = new org.apache.tomcat.jdbc.pool.DataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/javacode2018?characterEncoding=UTF-8");
dataSource.setUsername("root");
dataSource.setPassword("root123");
dataSource.setInitialSize(5);
//定义一个JdbcTemplate,用来方便执行数据库增删改查
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
//1.定义事务管理器,给其指定一个数据源(可以把事务管理器想象为一个人,这个人来负责事务的控制操作)
PlatformTransactionManager platformTransactionManager = new DataSourceTransactionManager(dataSource);
//2.定义事务属性:TransactionDefinition,TransactionDefinition可以用来配置事务的属性信息,比如事务隔离级别、事务超时时间、事务传播方式、是否是只读事务等等。
TransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
//3.获取事务:调用platformTransactionManager.getTransaction开启事务操作,得到事务状态(TransactionStatus)对象
TransactionStatus transactionStatus = platformTransactionManager.getTransaction(transactionDefinition);
//4.执行业务操作,下面就执行2个插入操作
try {
System.out.println("before:" + jdbcTemplate.queryForList("SELECT * from t_user"));
jdbcTemplate.update("insert into t_user (name) values (?)", "test1-1");
jdbcTemplate.update("insert into t_user (name) values (?)", "test1-2");
//5.提交事务:platformTransactionManager.commit
platformTransactionManager.commit(transactionStatus);
} catch (Exception e) {
//6.回滚事务:platformTransactionManager.rollback
platformTransactionManager.rollback(transactionStatus);
System.out.println("after:" + jdbcTemplate.queryForList("SELECT * from t_user"));
## 编程式事务过程
编程式事务过程,我们简化了一下,如下:
```java
1、定义事务属性信息:TransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
2、定义事务管理器:PlatformTransactionManager platformTransactionManager = new DataSourceTransactionManager(dataSource);
3、获取事务:TransactionStatus transactionStatus = platformTransactionManager.getTransaction(transactionDefinition);
4、执行sql操作:比如上面通过JdbcTemplate的各种方法执行各种sql操作
5、提交事务(platformTransactionManager.commit)或者回滚事务(platformTransactionManager.rollback)
下面通过源码来解析上面4步操作,带大家理解原理。
## 1、定义事务属性信息(TransactionDefinition)
事务启动的过程中需要定义事务的一些配置信息,如:事务传播行为、隔离级别、超时时间、是否是只读事务、事务名称,spring中使用**TransactionDefinition接口**表示事务定义信息,下面看一下TransactionDefinition接口源码,主要有5个信息
- 事务传播行为
- 事务隔离级别
- 事务超时时间
- 是否是只读事务
- 事务名称
```java
public interface TransactionDefinition {
//传播行为:REQUIRED
int PROPAGATION_REQUIRED = 0;
//传播行为:REQUIRED
int PROPAGATION_SUPPORTS = 1;
//传播行为:REQUIRED
int PROPAGATION_MANDATORY = 2;
//传播行为:REQUIRED
int PROPAGATION_REQUIRES_NEW = 3;
//传播行为:REQUIRED
int PROPAGATION_NOT_SUPPORTED = 4;
//传播行为:REQUIRED
int PROPAGATION_NEVER = 5;
//传播行为:REQUIRED
int PROPAGATION_NESTED = 6;
//默认隔离级别
int ISOLATION_DEFAULT = -1;
//隔离级别:读未提交
int ISOLATION_READ_UNCOMMITTED = 1;
//隔离级别:读已提交
int ISOLATION_READ_COMMITTED = 2;
//隔离级别:可重复读
int ISOLATION_REPEATABLE_READ = 4;
//隔离级别:序列化的方式
int ISOLATION_SERIALIZABLE = 8;
//默认超时时间
int TIMEOUT_DEFAULT = -1;
//返回事务传播行为,默认是REQUIRED
default int getPropagationBehavior() {
return PROPAGATION_REQUIRED;
//返回事务的隔离级别
default int getIsolationLevel() {
return ISOLATION_DEFAULT;
//返回事务超时时间(秒)
default int getTimeout() {
return -1;
//是否是只读事务
default boolean isReadOnly() {
return false;
//获取事务名称
@Nullable
default String getName() {
return null;
//获取默认的事务定义信息
static TransactionDefinition withDefaults() {
return StaticTransactionDefinition.INSTANCE;
TransactionDefinition接口的实现类,比较多,我们重点关注用的比较多的2个
- **DefaultTransactionDefinition**:TransactionDefinition接口的默认的一个实现,编程式事务中通常可以使用这个
- **RuleBasedTransactionAttribute**:声明式事务中用到的是这个,这个里面对于事务回滚有一些动态匹配的规则,稍后在声明式事务中去讲。
![](https://itsoku.oss-cn-hangzhou.aliyuncs.com/itsoku/blog/article/129/7eba7fb0-5a31-413f-a309-0c9fc4dac9c3.png)
编程式事务中通常使用DefaultTransactionDefinition,如下:
```java
DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
//设置事务传播行为
transactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS);
//设置事务隔离级别
transactionDefinition.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
//设置是否是只读事务
transactionDefinition.setReadOnly(true);
//设置事务超时时间(s),事务超过了指定的时间还未结束,会抛异常
transactionDefinition.setTimeout(5);
//设置事务名称,这个名称可以随便设置,不过最好起个有意义的名字,在debug的过程中会输出
transactionDefinition.setName("class完整类名.方法名称");
下面进入第2步,定义事务管理器。
## 2、定义事务管理器(PlatformTransactionManager)
事务管理器,这是个非常重要的角色,可以把这货想象为一个人,spring就是靠这个人来管理事务的,负责:**获取事务、提交事务、回滚事务**,Spring中用**PlatformTransactionManager接口**表示事务管理器,接口中有三个方法
```java
public interface PlatformTransactionManager {
//通过事务管理器获取一个事务,返回TransactionStatus:内部包含事务的状态信息
TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
//根据事务的状态信息提交事务
void commit(TransactionStatus status) throws TransactionException;
//根据事务的状态信息回滚事务
void rollback(TransactionStatus status) throws TransactionException;
PlatformTransactionManager有多个实现类,用来应对不同的环境,比如你操作db用的是hibernate或者mybatis,那么用到的事务管理器是不一样的,常见的事务管理器实现有下面几个
![](https://itsoku.oss-cn-hangzhou.aliyuncs.com/itsoku/blog/article/129/2e525b2f-85b9-457d-b18c-8732d5fa847b.png)
**JpaTransactionManager**:如果你用jpa来操作db,那么需要用这个管理器来帮你控制事务。
**DataSourceTransactionManager**:如果你用是指定数据源的方式,比如操作数据库用的是:JdbcTemplate、mybatis、ibatis,那么需要用这个管理器来帮你控制事务。
**HibernateTransactionManager**:如果你用hibernate来操作db,那么需要用这个管理器来帮你控制事务。
**JtaTransactionManager**:如果你用的是java中的jta来操作db,这种通常是分布式事务,此时需要用这种管理器来控制事务。
我们的案例中使用的是JdbcTemplate来操作db,所以用的是`DataSourceTransactionManager`这个管理器。
```java
PlatformTransactionManager platformTransactionManager = new DataSourceTransactionManager(dataSource);
下面进入第3步,通过事务管理器来开启事务。
## 3、获取事务
下面源码我们以REQUIRED中嵌套一个REQUIRED_NEW来进行说明,也就是事务中嵌套一个新的事务。
### 3.1、getTransaction:获取事务
通过事务管理器的getTransactiongetTransaction(transactionDefinition)方法开启事务,传递一个TransactionDefinition参数
TransactionStatus transactionStatus = platformTransactionManager.getTransaction(transactionDefinition);
事务管理器我们用的是DataSourceTransactionManager,下面我们看一下DataSourceTransactionManager.getTransaction源码
```java
org.springframework.jdbc.datasource.DataSourceTransactionManager
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
//事务定义信息,若传入的definition如果为空,取默认的
TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
//@3.1-1:获取事务对象
Object transaction = doGetTransaction();
boolean debugEnabled = logger.isDebugEnabled();
//@3.1-2:当前是否存在事务
if (isExistingTransaction(transaction)) {
//@1-3:如果当前存在事务,走这里
return handleExistingTransaction(def, transaction, debugEnabled);
// 当前没有事务,走下面的代码
// 若事务传播级别是PROPAGATION_MANDATORY:要求必须存在事务,若当前没有事务,弹出异常
if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
} else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
//事务传播行为(PROPAGATION_REQUIRED|PROPAGATION_REQUIRES_NEW|PROPAGATION_NESTED)走这里
//@3.1-4:挂起事务
SuspendedResourcesHolder suspendedResources = suspend(null);
try {
//@3.1-5:是否开启新的事务同步
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
//@3.1-6:创建事务状态对象DefaultTransactionStatus,DefaultTransactionStatus是TransactionStatus的默认实现
DefaultTransactionStatus status = newTransactionStatus(def, transaction, true, newSynchronization, debugEnabled, suspendedResources);
//@3.1-7:doBegin用于开始事务
doBegin(transaction, def);
//@3.1-8:准备事务同步
prepareSynchronization(status, def);
//@3.1-9:返回事务状态对象
return status;
} catch (RuntimeException | Error ex) {
//@3.1-10:出现(RuntimeException|Error)恢复被挂起的事务
resume(null, suspendedResources);
throw ex;
} else {
//@3.1-11:其他事务传播行为的走这里(PROPAGATION_SUPPORTS、PROPAGATION_NOT_SUPPORTED、PROPAGATION_NEVER)
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
下面来看一下@3.1-1:doGetTransaction方法,用来获取事务对象
### 3.2、doGetTransaction:获取事务对象
```java
org.springframework.jdbc.datasource.DataSourceTransactionManager
protected Object doGetTransaction() {
//@3.2-1:创建数据源事务对象
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
//@3.2-2:是否支持内部事务
txObject.setSavepointAllowed(isNestedTransactionAllowed());
//@3.2-4:ConnectionHolder表示jdbc连接持有者,简单理解:数据的连接被丢到ConnectionHolder中了,ConnectionHolder中提供了一些方法来返回里面的连接,此处调用TransactionSynchronizationManager.getResource方法来获取ConnectionHolder对象
ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
//@3.2-5:将conHolder丢到DataSourceTransactionObject中,第二个参数表示是否是一个新的连接,明显不是的吗,新的连接需要通过datasource来获取,通过datasource获取的连接才是新的连接
txObject.setConnectionHolder(conHolder, false);
return txObject;
下面来看一下`@3.2-4`的代码,这个是重点了,这个用到了一个新的类`TransactionSynchronizationManager:事务同步管理器`,什么叫同步?一个事务过程中,被调用的方法都在一个线程中串行执行,就是同步;这个类中用到了很多ThreadLocal,用来在线程中存储事务相关的一些信息,,来瞅一眼
```java
public abstract class TransactionSynchronizationManager {
//存储事务资源信息
private static final ThreadLocal