Spring系列第47篇:通过源码解析事务原理,java面试问遇到的技术难点

//存储事务过程中的一些回调接口(TransactionSynchronization接口,这个可以在事务的过程中给开发者提供一些回调用的)

private static final ThreadLocal<Set> synchronizations =

new NamedThreadLocal<>(“Transaction synchronizations”);

//存储当前正在运行的事务的名称

private static final ThreadLocal currentTransactionName =

new NamedThreadLocal<>(“Current transaction name”);

//存储当前正在运行的事务是否是只读的

private static final ThreadLocal currentTransactionReadOnly =

new NamedThreadLocal<>(“Current transaction read-only status”);

//存储当前正在运行的事务的隔离级别

private static final ThreadLocal currentTransactionIsolationLevel =

new NamedThreadLocal<>(“Current transaction isolation level”);

//存储当前正在运行的事务是否是活动状态,事务启动的时候会被激活

private static final ThreadLocal actualTransactionActive =

new NamedThreadLocal<>(“Actual transaction active”);

//还有很多静态方法,主要是用来操作上面这些ThreadLocal的,这里就不列出的,大家可以去看看

}

下面来看TransactionSynchronizationManager.getResource代码

ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());

obtainDataSource()会返回事务管理器中的datasource对象

protected DataSource obtainDataSource() {

DataSource dataSource = getDataSource();

Assert.state(dataSource != null, “No DataSource set”);

return dataSource;

}

下面看TransactionSynchronizationManager.getResource的源码

public static Object getResource(Object key) {

//通过TransactionSynchronizationUtils.unwrapResourceIfNecessary(key)获取一个actualKey,我们传入的是datasouce,实际上最后actualKey和传入的datasource是一个对象

Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);

//调用doGetResource方法获取对应的value

Object value = doGetResource(actualKey);

return value;

}

doGetResource(actualKey)方法如下,内部会从resources这个ThreadLocal中获取获取数据ConnectionHolder对象,到目前为止,根本没有看到向resource中放入过数据,获取获取到的conHolder肯定是null了

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;

}

TransactionSynchronizationManager.getResource:可以理解为从resource ThreadLocal中查找transactionManager.datasource绑定的ConnectionHolder对象

到此,Object transaction = doGetTransaction()方法执行完毕,下面我们再回到getTransaction方法,第一次进来,上下文中是没有事务的,所以会走下面的@3.1-4的代码,当前没有事务,导致没有事务需要挂起,所以suspend方法内部可以先忽略

org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction

public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)

throws TransactionException {

//事务定义信息,若传入的definition如果为空,取默认的

TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());

//@3.1-1:获取事务对象

Object transaction = doGetTransaction();

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;

}

}

}

然后会执行下面代码

//@3.1-5:是否开启新的事务同步,事务同步是干嘛的,是spring在事务过程中给开发者预留的一些扩展点,稍后细说;大家先这么理解,每个新的事务newSynchronization都是true,开一个一个新的事务就会启动一个新的同步

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;

上面过程我们重点来说一下@3.1-7 和 @3.1-8

3.3、@3.1-7:doBegin 开启事务

org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin

protected void doBegin(Object transaction, TransactionDefinition definition) {

//数据源事务对象

DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;

//数据库连接

Connection con = null;

try {

//txObject.hasConnectionHolder()用来判断txObject.connectionHolder!=null,现在肯定是null,所以txObject.hasConnectionHolder()返回false

if (!txObject.hasConnectionHolder() ||

txObject.getConnectionHolder().isSynchronizedWithTransaction()) {

//调用transactionManager.datasource.getConnection()获取一个数据库连接

Connection newCon = obtainDataSource().getConnection();

//将数据库连接丢到一个ConnectionHolder中,放到txObject中,注意第2个参数是true,表示第一个参数的ConnectionHolder是新创建的

txObject.setConnectionHolder(new ConnectionHolder(newCon), true);

}

//连接中启动事务同步

txObject.getConnectionHolder().setSynchronizedWithTransaction(true);

//获取连接

con = txObject.getConnectionHolder().getConnection();

//获取隔离级别

Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);

//设置隔离级别

txObject.setPreviousIsolationLevel(previousIsolationLevel);

//设置是否是只读

txObject.setReadOnly(definition.isReadOnly());

//判断连接是否是自动提交的,如果是自动提交的将其置为手动提交

if (con.getAutoCommit()) {

//在txObject中存储一下连接自动提交老的值,用于在事务执行完毕之后,还原一下Connection的autoCommit的值

txObject.setMustRestoreAutoCommit(true);

//设置手动提交

con.setAutoCommit(false);

}

//准备事务连接

prepareTransactionalConnection(con, definition);

//设置事务活动开启

txObject.getConnectionHolder().setTransactionActive(true);

//根据事务定义信息获取事务超时时间

int timeout = determineTimeout(definition);

if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {

//设置连接的超时时间

txObject.getConnectionHolder().setTimeoutInSeconds(timeout);

}

//txObject中的ConnectionHolder是否是一个新的,确实是新的,所以这个地方返回true

if (txObject.isNewConnectionHolder()) {

//将datasource->ConnectionHolder丢到resource ThreadLocal的map中

TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());

}

}

}

重点来看一下下面这段代码

TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());

源码

org.springframework.transaction.support.TransactionSynchronizationManager#bindResource

public static void bindResource(Object key, Object value) throws IllegalStateException {

Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);

Map<Object, Object> map = resources.get();

if (map == null) {

map = new HashMap<>();

resources.set(map);

}

map.put(actualKey, value);

}

上面这段代码执行完毕之后,datasource->ConnectionHoloder(conn)被放到resources Threadloca的map中了。

3.4、@3.1-8:prepareSynchronization 准备事务同步

//@3.1-8:准备事务同步

prepareSynchronization(status, def);

源码如下,大家看一下,这个方法主要的作用是,开启一个新事务的时候,会将事务的状态、隔离级别、是否是只读事务、事务名称丢到TransactionSynchronizationManager中的各种对应的ThreadLocal中,方便在当前线程中共享这些数据。

org.springframework.transaction.support.AbstractPlatformTransactionManager#prepareSynchronization

protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) {

//如果是一个新的事务,status.isNewSynchronization()将返回true

if (status.isNewSynchronization()) {

TransactionSynchronizationManager.setActualTransactionActive(status.hasTransaction());

TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(

definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT ?

definition.getIsolationLevel() : null);

TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());

TransactionSynchronizationManager.setCurrentTransactionName(definition.getName());

//@3.4-1:初始化事务同步

TransactionSynchronizationManager.initSynchronization();

}

}

@3.4-1:初始化事务同步

org.springframework.transaction.support.TransactionSynchronizationManager

private static final ThreadLocal<Set> synchronizations =

new NamedThreadLocal<>(“Transaction synchronizations”);

//获取同步是否启动,新事务第一次进来synchronizations.get()是null,所以这个方法返回的是false

public static boolean isSynchronizationActive() {

return (synchronizations.get() != null);

}

//初始化事务同步,主要就是在synchronizations ThreadLocal中放一个LinkedHashSet

public static void initSynchronization() throws IllegalStateException {

if (isSynchronizationActive()) {

throw new IllegalStateException(“Cannot activate transaction synchronization - already active”);

}

synchronizations.set(new LinkedHashSet<>());

}

3.5、小结

获取事务的过程已经结束了,我们来看一下这个过程中做的一些关键的事情

1、获取db连接:从事务管理器的datasource中调用getConnection获取一个新的数据库连接,将连接置为手动提交

2、将datasource关联连接丢到ThreadLocal中:将第一步中获取到的连丢到ConnectionHolder中,然后将事务管理器的datasource->ConnectionHolder丢到了resource ThreadLocal中,这样我们可以通过datasource在ThreadLocal中获取到关联的数据库连接

3、准备事务同步:将事务的一些信息放到ThreadLocal中

4、事务方法中执行增删改查

以下面这个插入操作来看一下这个插入是如何参与到spring事务中的。

jdbcTemplate.update(“insert into t_user (name) values (?)”, “test1-1”);

最终会进入到jdbctemplate#execute方法里,无用代码我们给剔除,重点内部关注下面获取连接的方法

org.springframework.jdbc.core.JdbcTemplate#execute(org.springframework.jdbc.core.PreparedStatementCreator, org.springframework.jdbc.core.PreparedStatementCallback){

//获取数据库连接

Connection con = DataSourceUtils.getConnection(obtainDataSource());

//通过conn执行db操作

}

obtainDataSource()会返回jdbctemplate.datasource对象,下面重点来看DataSourceUtils.getConnection源码,最终会进入下面这个方法

org.springframework.jdbc.datasource.DataSourceUtils#doGetConnection

public static Connection doGetConnection(DataSource dataSource) throws SQLException {

//用jdbctemplate.datSource从TransactionSynchronizationManager的resouce ThreadLocal中获取对应的ConnectionHolder对象,在前面获取事务环节中,transactionManager.datasource->ConnectionHolder被丢到resouce ThreadLocal,而jdbctemplate.datSource和transactionManager.datasource是同一个对象,所以是可以获取到ConnectionHolder的,此时就会使用事务开启是的数据库连接

ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);

//conHolder不为空 && conHolder中有数据库连接对象

if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {

//返回conHolder中的数据库连接对象

return conHolder.getConnection();

}

//如果上面获取不到连接,会走这里,这里将会调用jdbctemplate.datasource.getConnection()从数据源中获取一个新的db连接

Connection con = fetchConnection(dataSource);

//将连接返回

return con;

}

可以得出一个结论:如果要让最终执行的sql受spring事务控制,那么事务管理器中datasource对象必须和jdbctemplate.datasource是同一个,这个结论在其他文章中说过很多次了,这里大家算是搞明白了吧。

5、提交事务

调用事务管理器的commit方法,提交事务

platformTransactionManager.commit(transactionStatus);

commit源码

org.springframework.transaction.support.AbstractPlatformTransactionManager#commit

public final void commit(TransactionStatus status) throws TransactionException {

//事务是否已经完成,此时还未完成,如果事务完成了,再来调用commit方法会报错

if (status.isCompleted()) {

throw new IllegalTransactionStateException(

“Transaction is already completed - do not call commit or rollback more than once per transaction”);

}

//事务状态

DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;

//defStatus.rollbackOnly是否是true,如果是true,说明事务状态被标注了需要回滚,此时走回滚逻辑

if (defStatus.isLocalRollbackOnly()) {

//走回滚逻辑

processRollback(defStatus, false);

return;

}

//提交事务过程

processCommit(defStatus);

}

processCommit源码

org.springframework.transaction.support.AbstractPlatformTransactionManager#processCommit

private void processCommit(DefaultTransactionStatus status) throws TransactionException {

try {

try {

//提交之前的回调(给开发提供的扩展点)

triggerBeforeCommit(status);

//事务完成之前的回调(给开发提供的扩展点)

triggerBeforeCompletion(status);

//是否是新事务,如果是新事务,将执行提交操作,比如传播行为是REQUIRED中嵌套了一个REQUIRED,那么内部的事务就不是新的事务,外部的事务是新事务

if (status.isNewTransaction()) {

//@5-1:执行提交操作

doCommit(status);

}

} catch (UnexpectedRollbackException ex) {

//事务完成之后执行的回调(给开发提供的扩展点)

triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);

throw ex;

} catch (RuntimeException | Error ex) {

//提交过程中有异常,执行回滚操作

doRollbackOnCommitException(status, ex);

throw ex;

}

try {

//事务commit之后,执行一些回调(给开发提供的扩展点)

triggerAfterCommit(status);

} finally {

//事务完成之后,执行一些回调(给开发提供的扩展点)

triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);

}

} finally {

//事务执行完毕之后,执行一些清理操作

cleanupAfterCompletion(status);

}

}

上面这个方法看起来挺长的,重点会做3件事情:

1、给开发提供的扩展点:以trigger开头的方法,是留给开发的扩展点,可以在事务执行的过程中执行一些回调,主要是在事务提交之前,提交之后,回滚之前,回滚之后,可以执行一些回调,也就是事务同步要干的事情,这个扩展点稍后说。

2、通过connection执行commit操作,对应上面的 @5-1 代码:doCommit(status);

3、完成之后执行清理操作:finally中执行 cleanupAfterCompletion(status);

来看看doCommit(status)方法,内部主要就是调用connection的commit()提交事务,如下:

org.springframework.jdbc.datasource.DataSourceTransactionManager#doCommit

protected void doCommit(DefaultTransactionStatus status) {

DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();

//从ConnectionHolder中获取Connection

Connection con = txObject.getConnectionHolder().getConnection();

//执行commit,提交数据库事务

con.commit();

}

cleanupAfterCompletion(status):清理操作

org.springframework.transaction.support.AbstractPlatformTransactionManager#cleanupAfterCompletion

private void cleanupAfterCompletion(DefaultTransactionStatus status) {

//将事务状态置为已完成

status.setCompleted();

//是否是新的事务同步

if (status.isNewSynchronization()) {

//将TransactionSynchronizationManager中的那些ThreadLoca中的数据都清除,会调用ThreadLocal的remove()方法清除数据

TransactionSynchronizationManager.clear();

}

//是否是新事务

if (status.isNewTransaction()) {

//执行清理操作

doCleanupAfterCompletion(status.getTransaction());

}

//是否有被挂起的事务

if (status.getSuspendedResources() != null) {

Object transaction = (status.hasTransaction() ? status.getTransaction() : null);

//恢复被挂起的事务

resume(transaction, (SuspendedResourcesHolder) status.getSuspendedResources());

}

}

doCleanupAfterCompletion源码

org.springframework.jdbc.datasource.DataSourceTransactionManager#doCleanupAfterCompletion

protected void doCleanupAfterCompletion(Object transaction) {

DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;

//是否是一个新的ConnectionHolder,如果是新的事务,那么ConnectionHolder是新的

if (txObject.isNewConnectionHolder()) {

//将transactionManager.datasource->ConnectionHolder从resource Threadlocal中干掉

TransactionSynchronizationManager.unbindResource(obtainDataSource());

}

//下面重置Connection,将Connection恢复到最原始的状态

Connection con = txObject.getConnectionHolder().getConnection();

try {

if (txObject.isMustRestoreAutoCommit()) {

//自动提交

con.setAutoCommit(true);

}

//恢复connction的隔离级别、是否是只读事务

DataSourceUtils.resetConnectionAfterTransaction(

con, txObject.getPreviousIsolationLevel(), txObject.isReadOnly());

} catch (Throwable ex) {

logger.debug(“Could not reset JDBC Connection after transaction”, ex);

}

//是否是新的连接

if (txObject.isNewConnectionHolder()) {

//释放连接,内部会调用conn.close()方法

DataSourceUtils.releaseConnection(con, this.dataSource);

}

//还原ConnectionHoloder到最初的状态

txObject.getConnectionHolder().clear();

}

终结一下,清理工作主要做的事情就是释放当前线程占有的一切资源,然后将被挂起的事务恢复

6、回滚事务

回滚的操作和提交的操作差不多的,源码我就不讲了,大家自己去看一下。

7、存在事务的情况如何走?

下面来看另外一个流程,REQUIRED中嵌套一个REQUIRED_NEW,然后走到REQUIRED_NEW的时候,代码是如何运行的?大致的过程如下

1、判断上线文中是否有事务

2、挂起当前事务

3、开启新事务,并执行新事务

4、恢复被挂起的事务

7.1、判断是否有事务:isExistingTransaction

判断上线文中是否有事务,比较简单,如下:

org.springframework.jdbc.datasource.DataSourceTransactionManager#isExistingTransaction

protected boolean isExistingTransaction(Object transaction) {

DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;

//txObject.connectionHolder!=null && connectionHolder事务处于开启状态(上面我们介绍过在doBegin开启事务的时候connectionHolder.transactionActive会被置为true)

return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());

}

7.2、若当前存在事务

我们再来看一下获取事务中,有事务如何走

org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction

public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {

//获取事务

Object transaction = doGetTransaction();

//是否存在事务

if (isExistingTransaction(transaction)) {

//存在事务会走这里

return handleExistingTransaction(def, transaction, debugEnabled);

}

}

当前存在事务,然后会进入handleExistingTransaction方法

org.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction

private TransactionStatus handleExistingTransaction(TransactionDefinition definition, Object transaction, boolean debugEnabled) throws TransactionException {

//当前有事务,被嵌套的事务传播行为是PROPAGATION_NEVER,抛出异常

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) {

//当前有事务,被嵌套的事务传播行为是PROPAGATION_NOT_SUPPORTED,那么将先调用suspend将当前事务挂起,然后以无事务的方式运行被嵌套的事务

//挂起当前事务

Object suspendedResources = suspend(transaction);

boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);

//以无事务的方式运行

return prepareTransactionStatus(

definition, null, false, newSynchronization, debugEnabled, suspendedResources);

}

if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {

//被嵌套的事务传播行为是PROPAGATION_REQUIRES_NEW,那么会先挂起当前事务,然后会重新开启一个新的事务

//挂起当前事务

SuspendedResourcesHolder suspendedResources = suspend(transaction);

try {

//下面的过程我们就不在再介绍了,之前有介绍过

boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);

DefaultTransactionStatus status = newTransactionStatus(

definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);

doBegin(transaction, definition);

prepareSynchronization(status, definition);

return status;

} catch (RuntimeException | Error beginEx) {

resumeAfterBeginException(transaction, suspendedResources, beginEx);

throw beginEx;

}

}

//其他的传播行为走下面。。。,暂时省略了

}

下面重点看事务挂起和事务的恢复操作。

7.3、事务挂起:suspend

事务挂起调用事务管理器的suspend方法,源码如下,主要做的事情:将当前事务中的一切信息保存到SuspendedResourcesHolder对象中,相当于事务的快照,后面恢复的时候用;然后将事务现场清理干净,主要是将一堆存储在ThreadLocal中的事务数据干掉。

org.springframework.transaction.support.AbstractPlatformTransactionManager#suspend

protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {

//当前事务同步是否被激活,如果是新事务,这个返回的是true

if (TransactionSynchronizationManager.isSynchronizationActive()) {

//挂起事务同步,这个地方会可以通过TransactionSynchronization接口给开发者提供了扩展点,稍后我们会单独介绍TransactionSynchronization接口,这个接口专门用来在事务执行过程中做回调的

List suspendedSynchronizations = doSuspendSynchronization();

try {

Object suspendedResources = null;

if (transaction != null) {

//@1:获取挂起的资源

suspendedResources = doSuspend(transaction);

}

//下面就是获取当前事务的各种信息(name,readyOnly,事务隔离级别,是否被激活)

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);

}

}

}

下面来看看@1:doSuspend(transaction)源码,主要就是将datasource->connectionHolder从resource ThreadLocal中解绑,然后将connectionHolder返回,下面这个方法实际上返回的就是connectionHolder对象

org.springframework.jdbc.datasource.DataSourceTransactionManager#doSuspend

protected Object doSuspend(Object transaction) {

DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;

//将connectionHolder置为null

txObject.setConnectionHolder(null);

//将datasource->connectionHolder从resource ThreadLocal中解绑,并返回被解绑的connectionHolder对象

return TransactionSynchronizationManager.unbindResource(obtainDataSource());

}

此时,当前的事务被挂起了,然后开启一个新的事务,新的事务的过程上面已经介绍过了,下面我们来看事务的恢复过程。

7.4、事务恢复:resume

事务挂起调用事务管理器的resume方法,源码如下,主要做的事情:通过SuspendedResourcesHolder对象中,将被挂起的事务恢复,SuspendedResourcesHolder对象中保存了被挂起的事务所有信息,所以可以通过这个对象来恢复事务。

org.springframework.transaction.support.AbstractPlatformTransactionManager#resume

protected final void resume(@Nullable Object transaction, @Nullable SuspendedResourcesHolder resourcesHolder)

throws TransactionException {

if (resourcesHolder != null) {

Object suspendedResources = resourcesHolder.suspendedResources;

if (suspendedResources != null) {

//恢复被挂起的资源,也就是将datasource->connectionHolder绑定到resource ThreadLocal中

doResume(transaction, suspendedResources);

}

List suspendedSynchronizations = resourcesHolder.suspendedSynchronizations;

//下面就是将数据恢复到各种ThreadLocal中

if (suspendedSynchronizations != null) {

TransactionSynchronizationManager.setActualTransactionActive(resourcesHolder.wasActive);

TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(resourcesHolder.isolationLevel);

TransactionSynchronizationManager.setCurrentTransactionReadOnly(resourcesHolder.readOnly);

TransactionSynchronizationManager.setCurrentTransactionName(resourcesHolder.name);

//恢复事务同步(将事务扩展点恢复)

doResumeSynchronization(suspendedSynchronizations);

}

}

}

8、事务执行过程中的回调接口: TransactionSynchronization

8.1、作用

spring事务运行的过程中,给开发者预留了一些扩展点,在事务执行的不同阶段,将回调扩展点中的一些方法。

比如我们想在事务提交之前、提交之后、回滚之前、回滚之后做一些事务,那么可以通过扩展点来实现。

8.2、扩展点的用法

1、定义事务TransactionSynchronization对象

TransactionSynchronization接口中的方法在spring事务执行的过程中会自动被回调

public interface TransactionSynchronization extends Flushable {

//提交状态

int STATUS_COMMITTED = 0;

//回滚状态

int STATUS_ROLLED_BACK = 1;

//状态未知,比如事务提交或者回滚的过程中发生了异常,那么事务的状态是未知的

int STATUS_UNKNOWN = 2;

//事务被挂起的时候会调用被挂起事务中所有TransactionSynchronization的resume方法

default void suspend() {

}

//事务恢复的过程中会调用被恢复的事务中所有TransactionSynchronization的resume方法

default void resume() {

}

//清理操作

@Override

default void flush() {

}

//事务提交之前调用

default void beforeCommit(boolean readOnly) {

}

//事务提交或者回滚之前调用

default void beforeCompletion() {

}

//事务commit之后调用

default void afterCommit() {

}

//事务完成之后调用

default void afterCompletion(int status) {

}

}

2、将TransactionSynchronization注册到当前事务中

通过下面静态方法将事务扩展点TransactionSynchronization注册到当前事务中

TransactionSynchronizationManager.registerSynchronization(transactionSynchronization)

看一下源码,很简单,丢到ThreadLocal中了

private static final ThreadLocal<Set> synchronizations =

new NamedThreadLocal<>(“Transaction synchronizations”);

public static void registerSynchronization(TransactionSynchronization synchronization)

throws IllegalStateException {

Set synchs = synchronizations.get();

if (synchs == null) {

throw new IllegalStateException(“Transaction synchronization is not active”);

}

synchs.add(synchronization);

}

当有多个TransactionSynchronization的时候,可以指定其顺序,可以实现org.springframework.core.Ordered接口,来指定顺序,从小大的排序被调用,TransactionSynchronization有个默认适配器TransactionSynchronizationAdapter,这个类实现了Ordered接口,所以,如果我们要使用的时候,直接使用TransactionSynchronizationAdapter这个类。

3、回调扩展点TransactionSynchronization中的方法

TransactionSynchronization中的方法是spring事务管理器自动调用的,本文上面有提交到,事务管理器在事务提交或者事务回滚的过程中,有很多地方会调用trigger开头的方法,这个trigger方法内部就会遍历当前事务中的transactionSynchronization列表,然后调用transactionSynchronization内部的一些指定的方法。

以事务提交的源码为例,来看一下

private void processCommit(DefaultTransactionStatus status) throws TransactionException {

triggerBeforeCommit(status);

triggerBeforeCompletion(status);

//…其他代码省略

}

triggerBeforeCommit(status)源码

protected final void triggerBeforeCommit(DefaultTransactionStatus status) {

if (status.isNewSynchronization()) {

TransactionSynchronizationUtils.triggerBeforeCommit(status.isReadOnly());

}

}

TransactionSynchronizationUtils.triggerBeforeCommit 源码

public static void triggerBeforeCommit(boolean readOnly) {

for (TransactionSynchronization synchronization : TransactionSynchronizationManager.getSynchronizations()) {

synchronization.beforeCommit(readOnly);

}

}

8.3、来个案例

1、执行sql

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
img

总结

面试建议是,一定要自信,敢于表达,面试的时候我们对知识的掌握有时候很难面面俱到,把自己的思路说出来,而不是直接告诉面试官自己不懂,这也是可以加分的。

以上就是蚂蚁技术四面和HR面试题目,以下最新总结的最全,范围包含最全MySQL、Spring、Redis、JVM等最全面试题和答案,仅用于参考

一份还热乎的蚂蚁金服面经(已拿Offer)面试流程4轮技术面+1轮HR

triggerBeforeCompletion(status);

//…其他代码省略

}

triggerBeforeCommit(status)源码

protected final void triggerBeforeCommit(DefaultTransactionStatus status) {

if (status.isNewSynchronization()) {

TransactionSynchronizationUtils.triggerBeforeCommit(status.isReadOnly());

}

}

TransactionSynchronizationUtils.triggerBeforeCommit 源码

public static void triggerBeforeCommit(boolean readOnly) {

for (TransactionSynchronization synchronization : TransactionSynchronizationManager.getSynchronizations()) {

synchronization.beforeCommit(readOnly);

}

}

8.3、来个案例

1、执行sql

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-jDhLKBac-1712113954366)]
[外链图片转存中…(img-KQF61EcH-1712113954367)]
[外链图片转存中…(img-dbL9vCf4-1712113954367)]
[外链图片转存中…(img-gwZAu88R-1712113954368)]
[外链图片转存中…(img-3OeIZuaQ-1712113954368)]
[外链图片转存中…(img-V3gh6LqM-1712113954369)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-vj4jvjHD-1712113954369)]

总结

面试建议是,一定要自信,敢于表达,面试的时候我们对知识的掌握有时候很难面面俱到,把自己的思路说出来,而不是直接告诉面试官自己不懂,这也是可以加分的。

以上就是蚂蚁技术四面和HR面试题目,以下最新总结的最全,范围包含最全MySQL、Spring、Redis、JVM等最全面试题和答案,仅用于参考

[外链图片转存中…(img-0v6Oi6QQ-1712113954369)]

  • 12
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值