系列文章目录
前言
上一篇自己简单实现了事务管理,接下来看看spring是如何实现的
一、spring的事务管理器DataSourceTransactionManager的使用
首先是配置类,配置了PlatformTransactionManager、jdbcTemplate和transactionTemplate
@Configuration
@ComponentScan("com.zcl.jdbc")
public class AppConfig {
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/j1910?characterEncoding=utf-8&useSSL=false");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
@Bean
public TransactionTemplate transactionTemplate(PlatformTransactionManager transactionManager) {
return new TransactionTemplate(transactionManager);
}
}
然后是Dao层,updateWithTransaction1方法是一个简单的使用,抛错后会回滚前面所有操作;updateWithTransaction2方法是对事务传播的使用,updateSupports()报错后不会影响updateNew()的事务提交,但是会导致其他的回滚。
@Repository
public class StudentDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private TransactionTemplate transactionTemplate;
/**不带事务*/
public void updateStudent(int id, String name) {
String sql = "update student set stu_name = ? where stu_id = ?";
jdbcTemplate.update(sql, name, id);
}
/**简单使用*/
public void updateWithTransaction1() {
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
try {
updateStudent(7,"zhangsan");
updateStudent(8,"lisi");
int i = 1/0;
// 更多数据库操作...
} catch (Exception e) {
status.setRollbackOnly(); // 触发回滚
throw e;
}
}
});
}
/**事务的传播*/
public void updateWithTransaction2() {
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
try {
updateStudent(7,"required");//最终回滚
updateNew();//最终成功
updateSupports();//最终回滚
} catch (Exception e) {
status.setRollbackOnly(); // 触发回滚
throw e;
}
}
});
}
public void updateSupports() {
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS);
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
try {
updateStudent(8,"supports");
int i = 1/0;
} catch (Exception e) {
status.setRollbackOnly(); // 触发回滚
throw e;
}
}
});
}
public void updateNew() {
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
try {
updateStudent(9,"new");
} catch (Exception e) {
status.setRollbackOnly(); // 触发回滚
throw e;
}
}
});
}
}
最后贴一点测试代码
public class MainTest {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
StudentDao studentDao = context.getBean(StudentDao.class);
studentDao.updateWithTransaction2();
}
}
二、spring的事务管理器DataSourceTransactionManager源码解析
上一篇介绍jdbc事务的使用、手写TransactionManager的使用都是为了抛砖引玉,是为了更好的分析DataSourceTransactionManager的源码。
我们在DataSourceTransactionManager的使用的例子中用到了3个关键的组件
JdbcTemplate
TransactionTemplate
DataSourceTransactionManager
下面逐个分析
1. JdbcTemplate
JdbcTemplate就是简化了数据库连接的获取关闭、sql的操作、结果集的封装,关键的方法如下:
public <T> T execute(StatementCallback<T> action) throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");
Connection con = DataSourceUtils.getConnection(obtainDataSource());
Statement stmt = null;
try {
stmt = con.createStatement();
applyStatementSettings(stmt);
T result = action.doInStatement(stmt);
handleWarnings(stmt);
return result;
}
catch (SQLException ex) {
// Release Connection early, to avoid potential connection pool deadlock
// in the case when the exception translator hasn't been initialized yet.
String sql = getSql(action);
JdbcUtils.closeStatement(stmt);
stmt = null;
DataSourceUtils.releaseConnection(con, getDataSource());
con = null;
throw translateException("StatementCallback", sql, ex);
}
finally {
JdbcUtils.closeStatement(stmt);
DataSourceUtils.releaseConnection(con, getDataSource());
}
}
我们主要看连接的获取DataSourceUtils.getConnection(obtainDataSource());
public static Connection doGetConnection(DataSource dataSource) throws SQLException {
Assert.notNull(dataSource, "No DataSource specified");
//从事务同步器中获取连接
ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {
conHolder.requested();
if (!conHolder.hasConnection()) {
logger.debug("Fetching resumed JDBC Connection from DataSource");
conHolder.setConnection(fetchConnection(dataSource));
}
return conHolder.getConnection();
}
logger.debug("Fetching JDBC Connection from DataSource");
Connection con = fetchConnection(dataSource);
...
}
从TransactionSynchronizationManager中获取连接,如果没有就重新从数据库获取连接。而TransactionSynchronizationManager中维护了一个ThreadLocal的map,所有事务相关的资源都放在这个map中,而ConnectionHolder就是以DataSource为key,以ConnectionHolder为value。所以这里获取连接就是从ThreadLocal中获取连接。
如果TranactionManager向ThreadLocal中存放了连接,那么JdbcTemplate执行sql是就能够ThreadLocal中获取到连接,那么就复用之前的连接(事务当然也是之前的事务),事务也就受TranactionManager管理了。如果TranactionManager没有向ThreadLocal中存放了连接,那么JdbcTemplate就获取不到连接,会新建自己的连接,执行完就提交事务了,事务也就不受TranactionManager管理了。所以TranactionManager管理事务的关键,就是执行sql时必须从ThreadLocal中获取到连接。所以现在应该明白为啥有时候事务会失效了吧(比如使用TransactionTemplate时没有使用jdbcTemplate,而是自己创建连接执行sql)。
private static final ThreadLocal<Map<Object, Object>> resources =
new NamedThreadLocal<>("Transactional resources");
是不是很熟悉,跟我们手写的MyNewTransactionManager中获取连接的思路是不是一样
2.TransactionTemplate
TransactionTemplate内部维护了一个transactionManager,同时继承了DefaultTransactionDefinition,可以设置事务的一些属性,主要就是事务的传播方式和隔离级别
public class TransactionTemplate extends DefaultTransactionDefinition{
private PlatformTransactionManager transactionManager;
...
}
并提供了一个执行事务的方法,具体的事务由transactionManager完成,这个又与我们手写的MyTransactionTemplate一样
public <T> T execute(TransactionCallback<T> action) throws TransactionException {
Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
}
else {
TransactionStatus status = this.transactionManager.getTransaction(this);
T result;
try {
result = action.doInTransaction(status);
}
catch (RuntimeException | Error ex) {
// Transactional code threw application exception -> rollback
rollbackOnException(status, ex);
throw ex;
}
catch (Throwable ex) {
// Transactional code threw unexpected exception -> rollback
rollbackOnException(status, ex);
throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
}
this.transactionManager.commit(status);
return result;
}
}
3.DataSourceTransactionManager
根据上面TransactionTemplate的execute方法的执行过程来看看DataSourceTransactionManager的主要源码
3.1 获取事务、挂起事务和开启事务
TransactionStatus status = this.transactionManager.getTransaction(this);
代码如下:
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException {
// Use defaults if no transaction definition given.
TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
//新建一个事务对象,并从TransactionSynchronizationManager中获取ConnectionHolder,设置到这个事务对象中,获取的ConnectionHolder用于后续判断是否存在上层事务
Object transaction = doGetTransaction();
boolean debugEnabled = logger.isDebugEnabled();
//如果存在上层事务,处理上层事务
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
return handleExistingTransaction(def, transaction, debugEnabled);
}
...
//根据传播方式,来决定是否开启事务
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) {
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
}
try {
return startTransaction(def, transaction, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error ex) {
resume(null, suspendedResources);
throw ex;
}
}
else {
// Create "empty" transaction: no actual transaction, but potentially synchronization.
if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
logger.warn("Custom isolation level specified but no actual transaction initiated; " +
"isolation level will effectively be ignored: " + def);
}
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
}
}
先介绍一个组件,因为后面会频繁提到
DataSourceTransactionObject: 事务对象,封装了ConnectionHolder和newConnectionHolder属性,ConnectionHolder是对连接的封装,其中有个非常重要的属性rollbackOnly,这个属性与我们手写MyNewTransactionManager时的rollbackOnly类似,是全局判断是否需要回滚的标记。 newConnectionHolder用于判断是否是新建的连接,如果是就要绑定到ThreadLocal中,同时在清理事务的时候将连接从ThreadLocal中解绑。当然DataSourceTransactionObject还有其他几个属性,比如是否允许设置保存点、保存上一层事务的隔离级别等,用于实现一些功能,从字面意思上就能理解,就不展开了,自己要用到的时候再来扒源码。现在只需要记住ConnectionHolder和newConnectionHolder就可以了
private boolean newConnectionHolder;
private boolean mustRestoreAutoCommit;
private ConnectionHolder connectionHolder;
private Integer previousIsolationLevel;
private boolean readOnly = false;
private boolean savepointAllowed = false;
再来看上面那段代码的逻辑:
1)新建一个事务对象,并从TransactionSynchronizationManager中获取ConnectionHolder,设置到这个事务对象中,获取的ConnectionHolder用于后续判断是否存在上层事务
2)判断这个事务对象中是否存在事务,如果存在,根据传播方式处理存在的事务。源码不难看懂,我就不贴代码了,逻辑如下
a.如果是NEVER,抛错
b.如果是NOT_SUPPORTED,挂起当前事务对象,不开启新的事务(新建一个事务对象为空的DefaultTransactionStatus返回)
c.如果是NEW,挂起当前事务对象,开启新事务(新建一个事务对象为新事务的DefaultTransactionStatus返回)
d.如果是NESTED,设置保存点(新建一个复用上层事务的DefaultTransactionStatus返回)
e.如果是SUPPORTS和REQUIRED,加入现有事务(新建一个复用上层事务的DefaultTransactionStatus返回)
3)如果不存在,根据传播方式,来决定是否开启事务
a.如果是REQUIRED、NEW、NESTED,挂起空事务,开启新事务(新建一个事务对象为新事务的DefaultTransactionStatus返回)
b.如果是其他的,不开启新的事务(新建一个事务对象为空的DefaultTransactionStatus返回)
这里的逻辑就是我们对spring事务的6种传播方式的理解。我们要剖析这个背后是怎么实现的,那么就需要搞清楚三个内容,一是挂起事务,二是开启事务,三是返回的DefaultTransactionStatus是什么?
我们先来看挂起事务
上面提到了两种,一是挂起当前事务,二是挂起空事务。区别就是挂起的事务对象是否为空
protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
//如果事务同步器中synchronizations中的set集合不为null,挂起生命周期方法
if (TransactionSynchronizationManager.isSynchronizationActive()) {
List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
try {
Object suspendedResources = null;
//如果连接不为空,挂起连接
if (transaction != null) {
suspendedResources = doSuspend(transaction);
}
String name = TransactionSynchronizationManager.getCurrentTransactionName();
TransactionSynchronizationManager.setCurrentTransactionName(null);
boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
TransactionSynchronizationManager.setCurrentTransactionReadOnly(false);
Integer isolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(null);
boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive();
TransactionSynchronizationManager.setActualTransactionActive(false);
return new SuspendedResourcesHolder(
suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);
}
catch (RuntimeException | Error ex) {
// doSuspend failed - original transaction is still active...
doResumeSynchronization(suspendedSynchronizations);
throw ex;
}
}
else if (transaction != null) {
// Transaction active but no synchronization active.
Object suspendedResources = doSuspend(transaction);
return new SuspendedResourcesHolder(suspendedResources);
}
else {
// Neither transaction nor synchronization active.
return null;
}
}
1)如果事务同步器中synchronizations中的set集合不为null(什么时候不为null呢,就是开启事务后初始化了),那么挂起set集合中的生命周期方法,挂起事务中的连接(如果连接不为空的话);挂起事务的名称、当前事务是否只读、当前事务隔离级别。其中生命周期方法就是每次提交、回滚事务前后、挂起恢复前后需要执行的方法,调用者直接在TransactionSynchronizationManager设置即可。
private static final Log logger = LogFactory.getLog(TransactionSynchronizationManager.class);
//这个资源主要就是ConnectionHolder
private static final ThreadLocal<Map<Object, Object>> resources =
new NamedThreadLocal<>("Transactional resources");
//生命周期方法
private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
new NamedThreadLocal<>("Transaction synchronizations");
//事务的名称
private static final ThreadLocal<String> currentTransactionName =
new NamedThreadLocal<>("Current transaction name");
//当前事务是否只读
private static final ThreadLocal<Boolean> currentTransactionReadOnly =
new NamedThreadLocal<>("Current transaction read-only status");
//当前事务隔离级别
private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
new NamedThreadLocal<>("Current transaction isolation level");
//是否激活
private static final ThreadLocal<Boolean> actualTransactionActive =
new NamedThreadLocal<>("Actual transaction active");
2)如果没有生命周期的方法synchronizations ,那么就只需要挂起事务(就是ConnectionHolder)。
3)如果既没有生命周期的方法也没有事务,那么就返回null
挂起就是将全局对象(各种ThreadLocal)中的值置为null或者还原为初始值,将被挂起的对象组成一个对象SuspendedResourcesHolder返回,保存在新建的TransactionStatus对象中,等待后续恢复事务
//返回当前的事务信息
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
//放到新建的TransactionStatus对象中,等待后续恢复事务
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
}
再来看开启事务
如果是开启新事务,都会调用下面的代码:
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
doBegin(transaction, definition);
prepareSynchronization(status, definition);
如果是不开启新事务
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
doBegin(transaction, definition);
prepareSynchronization(status, definition);
1)doBegin:就是新建连接、绑定连接到ThreadLocal、设置autocommit为false、设置read-only和隔离级别。如果不开启事务,这一步就没有
2)prepareSynchronization:初始化事务同步器,将@transactional中配置的隔离级别、ReadOnly、name设置到ThreadLocal中,然后给synchronizations设置一个空的set集合
再来看TransactionStatus对象
也就是TransactionStatus status = this.transactionManager.getTransaction(this)最后返回的对象。直接返回事务对象DataSourceTransactionObject就好了啊,为什么还要封装一层?当然是为了增加功能,其实刚刚讲挂起事务就能知道TransactionStatus的部分作用了(保存了事务信息啊),前面讲过事务对象DataSourceTransactionObject的结构,而TransactionStatus就是对DataSourceTransactionObject的封装
**DefaultTransactionStatus:**事务状态,对事务对象的进一步封装。结构如下:
//事务对象
private final Object transaction;
//是否是新的事务
private final boolean newTransaction;
private final boolean newSynchronization;
//挂起的同步信息
private final Object suspendedResources;
//是否回滚
private boolean rollbackOnly = false;
private boolean completed = false;
//保存点
private Object savepoint;
主要有四个功能:
a. newTransaction用于判断是否是新的事务,决定后续如果提交和回滚事务(跟我们手写TransactionObject中的newConnection作用差不多)
b. suspendedResources用于保存被挂起事务的资源
c. savepoint用于设置保存点。
d. rollbackOnly用于手动标记回滚。我们一般认为抛错了才会回滚,但这里让程序员自己根据业务决定是否回滚,也就是说,即使事务执行没有报错,程序员可以自己手动将rollbackOnly设置为true,从而使事务回滚。写一下代码示例解释一下,如下,没有报错但是最后能够回滚
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
try {
Student stu = queryStudent(9,"new");
if (stu == null){
status.setRollbackOnly(); // 受到触发回滚
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
3.2 执行sql
result = action.doInTransaction(status);
这个就不用讲了,这个是调用者自己实现的,调用者可以给TransactionStatus设置一些值,比如将localRollbackOnly设置为true
3.3 回滚事务
rollbackOnException(status, ex);
这个方法其实就是调用的transactionManager.rollback方法,部分代码如下:
private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
try {
...
//如果有保存点
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Rolling back transaction to savepoint");
}
status.rollbackToHeldSavepoint();
}
//如果是新的事务
else if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction rollback");
}
doRollback(status);
}
//如果不是新的事务
else {
// Participating in larger transaction
if (status.hasTransaction()) {
if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
doSetRollbackOnly(status);
}
}
}
...
finally {
cleanupAfterCompletion(status);
}
}
这个逻辑就很简单的,跟我们自己写的MyNewTransactionManager差不多啊
1)如果有保存点,回滚到保存点(NESTED传播方式)
2)如果是新的事务,提交事务
3)如果不是新的事务,将ConnectionHolder的rollbackOnly属性设为true
4)最后进行清理,这一步很重要,不要忽略,因为除了清理当前的一些资源以外,还将之前挂起的事务还原了,具体如下:
a.如果是新建连接,从threadlocal中解绑,释放连接
b.如果有挂起的上层事务,恢复上层事务
private void cleanupAfterCompletion(DefaultTransactionStatus status) {
status.setCompleted();
//这个先不管
if (status.isNewSynchronization()) {
TransactionSynchronizationManager.clear();
}
//如果是新建连接,从threadlocal中解绑,释放连接
if (status.isNewTransaction()) {
doCleanupAfterCompletion(status.getTransaction());
}
//如果有挂起的上层事务,恢复上层事务
if (status.getSuspendedResources() != null) {
if (status.isDebug()) {
logger.debug("Resuming suspended transaction after completion of inner transaction");
}
Object transaction = (status.hasTransaction() ? status.getTransaction() : null);
resume(transaction, (SuspendedResourcesHolder) status.getSuspendedResources());
}
}
3.4 提交事务
this.transactionManager.commit(status);
public final void commit(TransactionStatus status) throws TransactionException {
...
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
//如果localRollbackOnly为true
if (defStatus.isLocalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Transactional code has requested rollback");
}
processRollback(defStatus, false);
return;
}
//shouldCommitOnGlobalRollbackOnly默认为false,这里为true时就要手动去设置localRollbackOnly的值,我们一般用不到就不展开了
if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
}
processRollback(defStatus, true);
return;
}
processCommit(defStatus);
}
我们只需要关注主流程,processCommit(defStatus);
关键代码如下:
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
try {
...
if (status.hasSavepoint()) {
unexpectedRollback = status.isGlobalRollbackOnly();
status.releaseHeldSavepoint();
}
else if (status.isNewTransaction()) {
unexpectedRollback = status.isGlobalRollbackOnly();
doCommit(status);
}
}catch(
...
}
finally {
cleanupAfterCompletion(status);
}
1)如果有保存点,释放保存点,因为执行到这里肯定是没有报错的,保存点已经没有用了
2)如果是新事务,提交事务
3)如果不是新事务,什么都不干
4)最后进行清理
if (status.getSuspendedResources() != null) {
Object transaction = (status.hasTransaction() ? status.getTransaction() : null);
resume(transaction, (SuspendedResourcesHolder) status.getSuspendedResources());
}
3.5 小结
根据上面介绍,TransactionTemplate使用DataSourceTransactionManager管理事务的流程大致如下:
- 获取上层事务:很显然,第一次开启事务时为空,在事务中调用事务时才会有
- 挂起上层事务:挂起上层事务资源(连接、事务名称、事务传播方式、事务隔离级别、事务的生命周期方法),根据事务的传播方式来决定是挂起还是加入
- 开启本层事务:根据事务的传播方式来决定是否开启事务。如果是新建连接,还要绑定到ThreadLocal中
- 执行本层事务
- 提交或回滚事务:如果是新开启事务才会真正去提交和回滚,根据TransactionStatus的rollbackOnly属性(本层事务所有)、ConnectionHolder的rollbackOnly属性(全局所有),提交或回滚;如果不是新开启的事务,只会对ConnectionHolder的rollbackOnly属性进行标记。
- 然后清理当前事务,恢复挂起的上层事务
4. 问题
- 怎么理解事务是一层一层的?
每个事务方法执行的时候都会创建TransactionStatus用于记录当前事务的状态,例如当事务方法A调用事务方法B时,会将A的各种状态保存在B的TransactionStatus中,如果事务B又调用了事务C,以此类推,形成一个链表。执行完一个事务再根据链表回复前面的事务,所以是一层层的
总结
我们通过TransactionTemplate的使用,解读了DatasourceTransactionManager的源码
1)讲解了TransactionObject的结构,TransactionObject封装了ConnectionHolder,ConnectionHolder中有rollbackOnly标记。如果上下层事务是同一个事务,那么ConnectionHolder以及其中的rollbackOnly标记就是全局的。
2)讲解了TransactionStatus的结构,TransactionStatus封装了连接和被挂起的事务,并通过newTransaction这个标记用于决定是真正提交、回滚,还是对ConnectionHolder中的rollbackOnly进行标记
3)讲解了TransactionSynchronizationManager的结构,用于保存连接和被挂起的事务,从而能够实现事务的挂起和恢复
4)讲解了事务执行的整个流程:获取上层事务->挂起上层事务->开启本层事务->执行本层事务->提交和回滚事务->清理本层事务和恢复上层事务