上篇,在看这篇的时候,推荐先查看上篇。上篇我们主要介绍了JDBC的一些基本操作,以及Spring事务传播的一些概念,主要是从JDBC的角度来说的,这篇我们从Spring的角度来梳理下事务及其传播的使用以及源码的处理流程。
我们在前面的demo中获取Connection
是名称直接通过DriverManager.getConnection
创建的,但对于这个JDBC也有抽象一个接口也就是Datasource
。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OLer05ZF-1668333065095)(F:\MarkDown-File\知识点资料\JDBC与Spring事务及事务传播性原理解析.assets\image-20221113100132934.png)]
同时通过这个Datasource
,我们更常见的是线程池,例如Spring
默认使用的线程池实现HikariDataSource
。
public static void main(String[] args) throws SQLException, ClassNotFoundException {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/test");
config.setUsername("root");
config.setPassword("xxx");
config.setDriverClassName("com.mysql.cj.jdbc.Driver");
DataSource dataSource = new HikariDataSource(config);
Connection connection = dataSource.getConnection();
int insert = jdbcUtils.insert(connection);
System.out.println("-----insert ---- " + insert);
int i = delete(connection);
System.out.println("--------delete ------" + i );
}
我们上面说过,Spring事务的传播性是对我们demo的几种操作的抽象及具体的实现,下面我们就以PROPAGATION_REQUIRE_NEW
来说明下
PROPAGATION_REQUIRE_NEW 若当前没有事务,则新建一个事务。若当前存在事务,则新建 一个事务,新老事务相互独立。外部事务抛出异常回滚不会影响内部事务的正常提交
上面关于这个定义,我们从代码中来说:
若当前存在事务,则新建 一个事务,新老事务相互独立。我们可以将其理解为,如果调用当前方法的上面的方法已经有了事务(已经有了一个Connectiom
),我们就需要再新建一个事务来处理当前方法(获取一个新Connection
来操作当前方法,同时也需要上一个事务的信息进行挂起,也就是暂时保存,例如上一个Connection
,由于同时会有很多线程操作,所以这里一般会用到ThreadLocal
),也就是到时如果当前方法发生异常需要回滚的话,就回滚当前方法的sql,而不影响其他调用当前方法的上面的方法的执行(这里其实与PROPAGATION_NESTED
,有点类似,但他们两个不是一个概念,因为PROPAGATION_NESTED
用到是同一个Connection
,而这里用的是两个Connnection
)。
@Transactional(propagation = Propagation.REQUIRED)
public void studentOrderAdd()
{
// Propagation.REQUIRES_NEW
studentService.add();
// Propagation.NEVER
insOrderService.add();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void add()
{
Student student = new Student();
student.setAge((byte) 30);
student.setName("瑞环"+Math.random());
studentMapper.insert(student);
}
@Transactional(propagation = Propagation.NEVER)
public int add()
{
InsOrder insOrder = new InsOrder();
insOrder.setName("订单"+Math.random());
insOrder.setAge((int) Math.random()*100);
return insOrderMapper.insert(insOrder);
}
可以看到目前我们这个demo,在最外面我们是设置的Propagation.REQUIRED
,也就是需要事务,如果没有就会建一个事务。然后对于studentService.add()
我们设置的是Propagation.REQUIRES_NEW
,也就是会新建一个事务,与studentOrderAdd
的事务是分开的,互不影响。然后对于insOrderService.add()
方法,我们设置的是Propagation.NEVER
,也就是不需要事务,当它的上面由于studentOrderAdd()
是已经创建了,所以其就会不执行。然后对于这个整体来说,我们就可以知道,最后Student
会插入成功,然后Order
就不会执行。
下面我们改一下demo,也就是将studentService.add()
,改为Propagation.REQUIRED
,也就是它会与上面发放用一个事务。
@Transactional(propagation = Propagation.REQUIRED)
public void studentOrderAdd()
{
// Propagation.REQUIRED
studentService.add();
// Propagation.NEVER
insOrderService.add();
}
可以看到这次我们两张表都没有数据。
上面我们是通过简单demo说明了下不同事务传播机制的区别,要具体了解几种事务传播的操作可以搜索其他博文,这方面的博文应该有很多。
下面我们就来具体分析下Spring事务相关的源码
关于事务的入口逻辑是在TransactionInterceptor
中处理。首先是通过方法获取其的事务描述,例如事务的传播类型、隔离级别:
然后再获取其的事务管理器,因为我们的事务注解@Transactional
是能指定对应的事务管理器的。
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
TransactionAttributeSource tas = getTransactionAttributeSource();
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
final TransactionManager tm = determineTransactionManager(txAttr);
//编程式事务、先不管
PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
Object retVal;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
............
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
..............
}
}
这里就是Spring
事务的核心处理逻辑了,获取到事务处理后,然后再获取到当期线程的事务信息TransactionInfo
,再执行业务方法,通过invocation.proceedWithInvocation();
,当执行业务方法失败的话,就通过completeTransactionAfterThrowing
方法,不然的话,就通过commitTransactionAfterReturning
,进行提交。
protected static final class TransactionInfo {
@Nullable
private final PlatformTransactionManager transactionManager;
@Nullable
private final TransactionAttribute transactionAttribute;
private final String joinpointIdentification;
@Nullable
private TransactionStatus transactionStatus;
@Nullable
private TransactionInfo oldTransactionInfo;
我们可以其有oldTransactionInfo
,也就是当前事务方法的前面的事务方法,然后其他的transactionManager
、transactionStatus
是当前事务的信息记录。
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
// If no name specified, apply method identification as transaction name.
if (txAttr != null && txAttr.getName() == null) {
txAttr = new DelegatingTransactionAttribute(txAttr) {
@Override
public String getName() {
return joinpointIdentification;
}
};
}
TransactionStatus status = null;
if (txAttr != null) {
if (tm != null) {
status = tm.getTransaction(txAttr);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
"] because no transaction manager has been configured");
}
}
}
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
这里主要是通过tm.getTransaction(txAttr)
初始化创建、获取当前事务状态。
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException {
// Use defaults if no transaction definition given.
TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
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);
}
// Check definition settings for new transaction.
if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
}
........
}
@Override
protected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
这里就是获取当前事务状态信息,对于doGetTransaction()
方法,获取DataSourceTransactionObject
,也就是当前的ConnectionHolder
,也就是JDBC中的Connection
,获取当前线程的Connection
。如果获取不到,也就是当前线程还没有事务,conHolder
就会为空。
public class ConnectionHolder extends ResourceHolderSupport {
@Nullable
private ConnectionHandle connectionHandle;
@Nullable
private Connection currentConnection;
public ConnectionHolder(ConnectionHandle connectionHandle) {
Assert.notNull(connectionHandle, "ConnectionHandle must not be null");
this.connectionHandle = connectionHandle;
}
private static final ThreadLocal<Map<Object, Object>> resources =
new NamedThreadLocal<>("Transactional resources");
.............
private static Object doGetResource(Object actualKey) {
Map<Object, Object> map = resources.get();
if (map == null) {
return null;
}
Object value = map.get(actualKey);
........
return value;
}
获取到这个后,再是通过isExistingTransaction(transaction)
,判断当前线程是不是已经有了事务。
@Override
protected boolean isExistingTransaction(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());
}
这个方法主要就是的判断依据就是ConnectionHolder
,看ConnectionHolder
有没有,以及是否被激活
public boolean hasConnectionHolder() {
return (this.connectionHolder != null);
}
如果有并被激活,我们的代码逻辑就是走的return handleExistingTransaction(def, transaction, debugEnabled);
处理。
如果还没有事务,就是对几种不同传播机制进行处理:
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
return handleExistingTransaction(def, transaction, debugEnabled);
}
// Check definition settings for new transaction.
if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
}
// No existing transaction found -> check propagation behavior to find out how to proceed.
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);
try {
return startTransaction(def, transaction, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error ex) {
resume(null, suspendedResources);
throw ex;
}
}
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
}
如果是PROPAGATION_MANDATORY
,也就是当前事务方法一定也运行在已经有事务的环境下,不然就抛出异常No existing transaction found for transaction marked with propagation 'mandatory'
。
而另外的几种TransactionDefinition.PROPAGATION_REQUIRED
、PROPAGATION_REQUIRES_NEW
、PROPAGATION_NESTED
,其都是自己本身如果不满足要求,能自己直接创建事务。我们可以看到如果走的是这个逻辑分支,然后会调用suspend
方法,这个方法主要是挂起当前线程中本身已存在的事务信息。当我们注意。
protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
if (TransactionSynchronizationManager.isSynchronizationActive()) {
List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
try {
Object suspendedResources = null;
if (transaction != null) {
suspendedResources = doSuspend(transaction);
}
//下面主要是将当前线程的事务描叙内容设置为null,也就是还没有激活状态
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;
}
}
但我们注意,我们目前还没有事务,也就是TransactionSynchronizationManager.isSynchronizationActive()
与transaction != null
都是不满足的,所以我们这里返回的是null
。同时这个方法的主要是doSuspendSynchronization()
,这个主要是获取到当前线程已经存在的事务描叙信息,例如当前事务方法前面事务方法的描述。同时在调用suspend
是,如果已经有事务,其会通过doSuspend(transaction)
,来处理挂起逻辑:
protected Object doSuspend(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
txObject.setConnectionHolder(null);
return TransactionSynchronizationManager.unbindResource(obtainDataSource());
}
也就是将线程已经持有的ConnectionHolder
,设置为null
,同时将绑定在当前线程的连接信息下掉(从ThreadLocal移除),这样的话,后面需要事务的话,就再通过Datasource
新获取一个Connection
来操作当前方法的事务。
private static Object doUnbindResource(Object actualKey) {
Map<Object, Object> map = resources.get();
if (map == null) {
return null;
}
Object value = map.remove(actualKey);
.........
return value;
}
然后再是正式通过doBegin
,来初始化当前事务方法的各种信息。
3)、startTransaction方法
private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
if (!txObject.hasConnectionHolder() ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
Connection newCon = obtainDataSource().getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
.................
txObject.getConnectionHolder().setTransactionActive(true);
............
// Bind the connection holder to the thread.
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
}
}
catch (Throwable ex) {
......... }
}
这里首先是判断当前有没有Connection
,没有就通过数据源创建一个Connection newCon = obtainDataSource().getConnection();
。然后再通过TransactionSynchronizationManager.bindResource
,将当前事务方法的ConnectionHolder
绑定到resources
线程上下文中。
public static void bindResource(Object key, Object value) throws IllegalStateException {
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
Assert.notNull(value, "Value must not be null");
Map<Object, Object> map = resources.get();
// set ThreadLocal Map if none found
if (map == null) {
map = new HashMap<>();
resources.set(map);
}
Object oldValue = map.put(actualKey, value);
........
}
上面是如果我们还没有事务的处理,下面我们回到前面看下有事务的处理,也就是handleExistingTransaction
的逻辑。
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException(
"Existing transaction found for transaction marked with propagation 'never'");
}
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
Object suspendedResources = suspend(transaction);
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
return startTransaction(definition, transaction, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error beginEx) {
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
}
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
if (debugEnabled) {
logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
}
if (useSavepointForNestedTransaction()) {
DefaultTransactionStatus status =
prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
status.createAndHoldSavepoint();
return status;
}
else {
// Nested transaction through nested begin and commit/rollback calls.
// Usually only for JTA: Spring synchronization might get activated here
// in case of a pre-existing JTA transaction.
return startTransaction(definition, transaction, debugEnabled, null);
}
}
............
}
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}
首先是PROPAGATION_NEVER
,也就是不需要事务,如果有的话,抛出异常Existing transaction found for transaction marked with propagation 'never'
。
然后是PROPAGATION_NOT_SUPPORTED
,也就是不在事务中执行,Object suspendedResources = suspend(transaction);
,可以看到这里首先会将线程已经有的事务挂起。
而如果是PROPAGATION_REQUIRES_NEW
,其也会调suspend(transaction)
挂起当前线程的事务,但这里会再通过startTransaction
来新开一个事务。也就是在startTransaction
方法调用doBegin
方法时,会再获取一次Connection
,这个可以再去看``。但这里我们注意,这里与第一次开启,也就是当前线程还没有事务不同的是SuspendedResourcesHolder
也就是当前线程已存在的事务是有内容的,这个信息是用来当前方法事务处理完后,恢复线程以前事务用的。
再之后是TransactionDefinition.PROPAGATION_NESTED
,这个会用到保存点,也就是status.createAndHoldSavepoint()
,其不会新获取Connection
:
public void createAndHoldSavepoint() throws TransactionException {
setSavepoint(getSavepointManager().createSavepoint());
}
我们了解这些后,再回到最前面的invokeWithinTransaction
方法,来处理回滚、或提交的内容。
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
try {
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {
logger.error("Application exception overridden by rollback exception", ex);
ex2.initApplicationException(ex);
throw ex2;
}
catch (RuntimeException | Error ex2) {
logger.error("Application exception overridden by rollback exception", ex);
throw ex2;
}
}
else {
// We don't roll back on this exception.
// Will still roll back if TransactionStatus.isRollbackOnly() is true.
try {
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {
logger.error("Application exception overridden by commit exception", ex);
ex2.initApplicationException(ex);
throw ex2;
}
catch (RuntimeException | Error ex2) {
logger.error("Application exception overridden by commit exception", ex);
throw ex2;
}
}
}
}
这里有两个,一个是回滚,当是我们指定的异常时,就回滚(可以通过@Transactional
指定只发生指定的异常才回滚),不然就提交。
private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
try {
boolean unexpectedRollback = unexpected;
try {
triggerBeforeCompletion(status);
if (status.hasSavepoint()) {
status.rollbackToHeldSavepoint();
}
else if (status.isNewTransaction()) {
doRollback(status);
}
else {
// Participating in larger transaction
if (status.hasTransaction()) {
if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
doSetRollbackOnly(status);
}
}
// Unexpected rollback only matters here if we're asked to fail early
if (!isFailEarlyOnGlobalRollbackOnly()) {
unexpectedRollback = false;
}
}
}
catch (RuntimeException | Error ex) {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
throw ex;
}
............
}
finally {
cleanupAfterCompletion(status);
}
}
回滚主要两种,一种就是保存点,另一直是整个事务回滚
public void rollbackToHeldSavepoint() throws TransactionException {
Object savepoint = getSavepoint();
if (savepoint == null) {
throw new TransactionUsageException(
"Cannot roll back to savepoint - no savepoint associated with current transaction");
}
getSavepointManager().rollbackToSavepoint(savepoint);
getSavepointManager().releaseSavepoint(savepoint);
setSavepoint(null);
}
protected void doRollback(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
}
try {
con.rollback();
}
catch (SQLException ex) {
throw translateException("JDBC rollback", ex);
}
}
另一个就是我们业务方法没有问题,正常执行,就会通过commitTransactionAfterReturning
方法来提交事务。
protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
}
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
}
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
try {
boolean beforeCompletionInvoked = false;
try {
boolean unexpectedRollback = false;
prepareForCommit(status);
triggerBeforeCommit(status);
triggerBeforeCompletion(status);
beforeCompletionInvoked = true;
if (status.hasSavepoint()) {
unexpectedRollback = status.isGlobalRollbackOnly();
status.releaseHeldSavepoint();
}
else if (status.isNewTransaction()) {
unexpectedRollback = status.isGlobalRollbackOnly();
doCommit(status);
}
else if (isFailEarlyOnGlobalRollbackOnly()) {
unexpectedRollback = status.isGlobalRollbackOnly();
}
}
.........
// Trigger afterCommit callbacks, with an exception thrown there
// propagated to callers but the transaction still considered as committed.
try {
triggerAfterCommit(status);
}
finally {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
}
}
finally {
cleanupAfterCompletion(status);
}
}
同时在这里我们要注意,不管是回滚、还是提交,其最后都会调用cleanupAfterCompletion
方法,这个方法是我们前面提到的,用来恢复当前线程的事务环境的,也就是当前方法的事务处理完了,获取前面方法的事务环境。
private void cleanupAfterCompletion(DefaultTransactionStatus status) {
status.setCompleted();
if (status.isNewSynchronization()) {
TransactionSynchronizationManager.clear();
}
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个逻辑,如果是新的同步信息,清理同步上下文。
public static void clear() {
synchronizations.remove();
currentTransactionName.remove();
currentTransactionReadOnly.remove();
currentTransactionIsolationLevel.remove();
actualTransactionActive.remove();
}
如果是新事务,释放当前连接:
protected void doCleanupAfterCompletion(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
// Remove the connection holder from the thread, if exposed.
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.unbindResource(obtainDataSource());
}
// Reset connection.
Connection con = txObject.getConnectionHolder().getConnection();
try {
if (txObject.isMustRestoreAutoCommit()) {
con.setAutoCommit(true);
}
DataSourceUtils.resetConnectionAfterTransaction(
con, txObject.getPreviousIsolationLevel(), txObject.isReadOnly());
}
catch (Throwable ex) {
logger.debug("Could not reset JDBC Connection after transaction", ex);
}
if (txObject.isNewConnectionHolder()) {
DataSourceUtils.releaseConnection(con, this.dataSource);
}
txObject.getConnectionHolder().clear();
}
最后是主要逻辑,也就是我们前面强调的SuspendedResources
信息,resume(transaction, (SuspendedResourcesHolder) status.getSuspendedResources())
方法的调用。
我们修改我们前面demo:
@Transactional(propagation = Propagation.REQUIRED)
public void add()
{
// Propagation.REQUIRED
studentService.add();
// Propagation.REQUIRES_NEW
insOrderService.add();
}
将其改为这种组合,看其执行完insOrderService.add()
后,SuspendedResources
的值。
我们可以看到,上一个事务相关的信息,也就是com.fev.spring.boot.demo.service.StudentOrderService.add
,它与当前方法事务用的Connection
是不同的。然后这里就会通过resume
方法来恢复
protected final void resume(@Nullable Object transaction, @Nullable SuspendedResourcesHolder resourcesHolder)
throws TransactionException {
if (resourcesHolder != null) {
Object suspendedResources = resourcesHolder.suspendedResources;
if (suspendedResources != null) {
doResume(transaction, suspendedResources);
}
List suspendedSynchronizations = resourcesHolder.suspendedSynchronizations;
if (suspendedSynchronizations != null) {
TransactionSynchronizationManager.setActualTransactionActive(resourcesHolder.wasActive);
TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(resourcesHolder.isolationLevel);
TransactionSynchronizationManager.setCurrentTransactionReadOnly(resourcesHolder.readOnly);
TransactionSynchronizationManager.setCurrentTransactionName(resourcesHolder.name);
doResumeSynchronization(suspendedSynchronizations);
}
}
}
public abstract class TransactionSynchronizationManager {
private static final Log logger = LogFactory.getLog(TransactionSynchronizationManager.class);
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");
可以看到会将上一个事务的信息,设置到线程上下文中。再是doResumeSynchronization
方法执行,获取上一个Connection
的信息。
private void doResumeSynchronization(List<TransactionSynchronization> suspendedSynchronizations) {
TransactionSynchronizationManager.initSynchronization();
for (TransactionSynchronization synchronization : suspendedSynchronizations) {
synchronization.resume();
TransactionSynchronizationManager.registerSynchronization(synchronization);
}
}
public void resume() {
if (this.holderActive) {
LOGGER.debug(() -> "Transaction synchronization resuming SqlSession [" + this.holder.getSqlSession() + "]");
TransactionSynchronizationManager.bindResource(this.sessionFactory, this.holder);
}
}
重新绑定前面的holder
到当前线程中。
上面我们大体梳理了下Spring事务以及传播机制相关的源码流程。其核心就是通过在线程中使用ThreadLocal对Connection
的获取、挂起、恢复的组装来实现不同的传播效果。