Spring事务补充代码
DataSourceTransactionObject
JdbcTransactionObjectSupport
// 数据库连接持有者
private ConnectionHolder connectionHolder;
// 上一个隔离级别
private Integer previousIsolationLevel;
// 是否只读
private boolean readOnly = false;
// 是否允许存在回滚点
private boolean savepointAllowed = false;
DataSourceTransactionObject
// 是否是新的数据库连接持有者
private boolean newConnectionHolder;
// 是否必须要自动提交
private boolean mustRestoreAutoCommit;
ConnectionHolder
在DataSourceTransactionObject中持有ConnectionHolder的引用,但是其实是JdbcTransactionObjectSupport持有的,因为DataSourceTransactionObject继承JdbcTransactionObjectSupport,所以在DataSourceTransactionObject也可以操作这个类。
看下属性:
// 获取得到数据库连接和归还数据库连接的
@Nullable
private ConnectionHandle connectionHandle;
// 当前的数据库连接
@Nullable
private Connection currentConnection;
// 当前线程中的事务活跃状态
private boolean transactionActive = false;
// 是否支持回滚掉
@Nullable
private Boolean savepointsSupported;
private int savepointCounter = 0;
而因为ConnectionHolder继承了ResourceHolderSupport,所以也继承了其中的属性:
// 在事务上是否有同步
private boolean synchronizedWithTransaction = false;
// 事务回滚标记!
private boolean rollbackOnly = false;
什么时候是新的数据库连接
首先会来尝试获取一下当前线程中是否有数据库连接存在
protected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
然后在doBegin方法中会来真正的进行设置
if (!txObject.hasConnectionHolder() || txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
// 真正的去获取得到数据库连接
Connection newCon = obtainDataSource().getConnection();
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
表示的是真正的去数据源中得到一个新的数据库连接的时候,才会将DataSourceTransactionObject中的newConnectionHolder设置为true。
表示的是创建的是新的数据库连接,而不是复用的数据库连接。这里会将创建出来的数据库连接封装到ConnectionHolder中,然后保存到DataSourceTransactionObject中来。
什么时候是新事务
我觉得,将conn.setAutoCommit(false),从这里开始算,是一个新事务。
在doBegin方法中:
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
....
con.setAutoCommit(false);
}
.....
txObject.getConnectionHolder().setTransactionActive(true);
因为将数据库连接设置自动提交为FALSE,所以在这里表示开启了一个新的事务。
开启了新事务之后,会将同步资源绑定到事务上。看下对应的代码:
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
这里设置了之后,稍后会把资源进行绑定。
什么时候将当前数据库连接绑定到当前线程上
也是在doBegin方法中
// Bind the connection holder to the thread.
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
}
如果是一个新的数据连接,那么会以数据源为key,value为ConnectionHolder保存当线程线程中来。
在TransactionSynchronizationManager中利用ThreadLocal来进行保存:
private static final ThreadLocal<Map<Object, Object>> resources =new NamedThreadLocal<>("Transactional resources");
然后这个时候,看下上面的什么时候是新的数据库连接中代码:
protected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
如果新的事务来了之后,这里的判断,并非又将事务给激活了(transactionActive=false),这是设置为false,表示的是新的事务
事务活跃状态
也在doBegin方法中,会来将数据库持有者来进行设置。
txObject.getConnectionHolder().setTransactionActive(true);
开启事务之新的同步器
这里的开启事务,包含了conn.setAutoCommit(false),但是也做了其他处理:
private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {
// true
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
// 这里处理过了
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
那么看得到默认的是事务状态中的代码:
protected DefaultTransactionStatus newTransactionStatus(
TransactionDefinition definition, @Nullable Object transaction, boolean newTransaction,
boolean newSynchronization, boolean debug, @Nullable Object suspendedResources) {
// 判断当前线程中的同步是否激活!如果为false,那么表示不是新的数据库连接
boolean actualNewSynchronization = newSynchronization &&
!TransactionSynchronizationManager.isSynchronizationActive();
return new DefaultTransactionStatus(
transaction, newTransaction, actualNewSynchronization,
definition.isReadOnly(), debug, suspendedResources);
}
可以看到,TransactionSynchronizationManager.isSynchronizationActive()=true的时候,表示的是当前数据库连接不是新创建的,而是上一次事务遗留的。
如果为false,那么表示的是上次线程中没有,需要新建一个。然后取反,以此确定是否是一个真正的新的同步器。如果复用之前的,逻辑上来说,不是一个新的,而是旧的。
事务同步器
上面新的事务开启了之后,下面将会来在事务上做一些同步处理,在startTransaction方法中的prepareSynchronization方法中实现:
首先判断是否是新的同步器,如果是的话,才会做一些同步操作:
protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) {
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());
// 初始化同步器
TransactionSynchronizationManager.initSynchronization();
}
}
重点看一下这里的事务同步器初始化:
public static void initSynchronization() throws IllegalStateException {
if (isSynchronizationActive()) {
throw new IllegalStateException("Cannot activate transaction synchronization - already active");
}
synchronizations.set(new LinkedHashSet<>());
}
可以看到如果是初始化了,那么表示当前事务中的同步器已经有初始化同步器了。
这里开始来创建新的LinkedHashSet集合来保存用户自定义的TransactionSynchronization。
Spring会将同步器保存到TransactionSynchronizationManager中的属性中来:
private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations = new NamedThreadLocal<>("Transaction synchronizations");
方便在后续提交或者是回滚中来进行一些列的操作。
在当前线程同步器集合中加入同步器
已经还没有进入到同步器之前,已经做了初始化,所以用户可以来做自定义注册同步器。
在TransactionSynchronizationManager类中的registerSynchronization方法中会来进行注册同步器:
public static void registerSynchronization(TransactionSynchronization synchronization)
throws IllegalStateException {
Assert.notNull(synchronization, "TransactionSynchronization must not be null");
Set<TransactionSynchronization> synchs = synchronizations.get();
if (synchs == null) {
throw new IllegalStateException("Transaction synchronization is not active");
}
synchs.add(synchronization);
}
因为使用的是LinkedHashSet来进行保存的,所以会按照添加的顺序来执行同步器中的方法。
那么来看下TransactionSynchronization接口中的方法:
挂起同步资源
default void suspend() {
}
恢复同步资源
default void resume() {
}
提交之前做的处理
default void beforeCommit(boolean readOnly) {
}
事务完成之前做的处理
default void beforeCompletion() {
}
事务提交之后做的处理
default void afterCommit() {
}
事务完成之后做的处理
default void afterCompletion(int status) {
}
在当前线程事务中使用同步器
同步器的使用将会在事务提交或者回滚之前来使用,那么直接去看一下对应的处理代码:
invokeWithinTransaction
看下这个方法中的提交和回滚
提交
commitTransactionAfterReturning(txInfo);
直接看下里面的processCommit提交方法
triggerBeforeCommit(status);
triggerBeforeCompletion(status);
...........
try {
triggerAfterCommit(status);
}
finally {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
}
回滚
看一下对应的回滚方法:
completeTransactionAfterThrowing(txInfo, ex);
跟着来到:
processRollback(defStatus, false);
继续看:
triggerBeforeCompletion(status);
..........
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
在事务完成之前和事务完成之后做的事情。
但是没有类似事务提交前和提交后对应的回滚前和回滚后的方法来进行处理。
看一下对应的处理方式:
触发事务完成之前的代码:triggerBeforeCompletion
protected final void triggerBeforeCompletion(DefaultTransactionStatus status) {
if (status.isNewSynchronization()) {
TransactionSynchronizationUtils.triggerBeforeCompletion();
}
}
public static void triggerBeforeCompletion() {
for (TransactionSynchronization synchronization : TransactionSynchronizationManager.getSynchronizations()) {
try {
synchronization.beforeCompletion();
}
catch (Throwable ex) {
logger.debug("TransactionSynchronization.beforeCompletion threw exception", ex);
}
}
}
触发事务完成之后的代码:triggerAfterCompletion
private void triggerAfterCompletion(DefaultTransactionStatus status, int completionStatus) {
if (status.isNewSynchronization()) {
List<TransactionSynchronization> synchronizations = TransactionSynchronizationManager.getSynchronizations();
TransactionSynchronizationManager.clearSynchronization();
if (!status.hasTransaction() || status.isNewTransaction()) {
// No transaction or new transaction for the current scope ->
// invoke the afterCompletion callbacks immediately
invokeAfterCompletion(synchronizations, completionStatus);
}
else if (!synchronizations.isEmpty()) {
// Existing transaction that we participate in, controlled outside
// the scope of this Spring transaction manager -> try to register
// an afterCompletion callback with the existing (JTA) transaction.
registerAfterCompletionWithExistingTransaction(status.getTransaction(), synchronizations);
}
}
}
public static void invokeAfterCompletion(@Nullable List<TransactionSynchronization> synchronizations,
int completionStatus) {
if (synchronizations != null) {
for (TransactionSynchronization synchronization : synchronizations) {
try {
synchronization.afterCompletion(completionStatus);
}
catch (Throwable ex) {
logger.debug("TransactionSynchronization.afterCompletion threw exception", ex);
}
}
}
}
然后利用for循环挨个进行遍历即可。
spring整合mybatis时操作
解决sqlsession不安全的情况,利用了SqlSessionTemplate,看一下对应的SqlSessionInterceptor中的invoke方法是如何来获取得到SqlSession
重点是获取方法:
registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);
看下具体实现:
private static void registerSessionHolder(SqlSessionFactory sessionFactory, ExecutorType executorType,
PersistenceExceptionTranslator exceptionTranslator, SqlSession session) {
SqlSessionHolder holder;
// 事务事务激活了!说明是在一个事务中
if (TransactionSynchronizationManager.isSynchronizationActive()) {
Environment environment = sessionFactory.getConfiguration().getEnvironment();
if (environment.getTransactionFactory() instanceof SpringManagedTransactionFactory) {
LOGGER.debug(() -> "Registering transaction synchronization for SqlSession [" + session + "]");
// 创建SqlSessionHolder,sqlsession和执行器类型
holder = new SqlSessionHolder(session, executorType, exceptionTranslator);
// 绑定到当前线程中来,key是sessionFactory,对应的值是:SqlSessionHolder
TransactionSynchronizationManager.bindResource(sessionFactory, holder);
// 注册这里的同步器
TransactionSynchronizationManager
.registerSynchronization(new SqlSessionSynchronization(holder, sessionFactory));
holder.setSynchronizedWithTransaction(true);
holder.requested();
} else {
if (TransactionSynchronizationManager.getResource(environment.getDataSource()) == null) {
LOGGER.debug(() -> "SqlSession [" + session
+ "] was not registered for synchronization because DataSource is not transactional");
} else {
throw new TransientDataAccessResourceException(
"SqlSessionFactory must be using a SpringManagedTransactionFactory in order to use Spring transaction synchronization");
}
}
} else {
LOGGER.debug(() -> "SqlSession [" + session
+ "] was not registered for synchronization because synchronization is not active");
}
}
重写了TransactionSynchronization方法
但是这里是继承了TransactionSynchronizationAdapter,因为TransactionSynchronizationAdapter也是实现了TransactionSynchronization方法。
看下接口,但是类上添加了@Deprecated注解,表示的是过期了,但是可以使用!其实这里也是相当于是重写TransactionSynchronization接口中的方法而已
public abstract class TransactionSynchronizationAdapter implements TransactionSynchronization, Ordered {
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
@Override
public void suspend() {
}
@Override
public void resume() {
}
@Override
public void flush() {
}
@Override
public void beforeCommit(boolean readOnly) {
}
@Override
public void beforeCompletion() {
}
@Override
public void afterCommit() {
}
@Override
public void afterCompletion(int status) {
}
}
那么来看下重写方法做了什么事情?
public void suspend() {
if (this.holderActive) {
LOGGER.debug(() -> "Transaction synchronization suspending SqlSession [" + this.holder.getSqlSession() + "]");
TransactionSynchronizationManager.unbindResource(this.sessionFactory);
}
}
public void resume() {
if (this.holderActive) {
LOGGER.debug(() -> "Transaction synchronization resuming SqlSession [" + this.holder.getSqlSession() + "]");
TransactionSynchronizationManager.bindResource(this.sessionFactory, this.holder);
}
}
public void beforeCommit(boolean readOnly) {
// 真正激活了事务才会来提交事务
if (TransactionSynchronizationManager.isActualTransactionActive()) {
try {
LOGGER.debug(() -> "Transaction synchronization committing SqlSession [" + this.holder.getSqlSession() + "]");
// 走到动态代理中去执行
this.holder.getSqlSession().commit();
} catch (PersistenceException p) {
if (this.holder.getPersistenceExceptionTranslator() != null) {
DataAccessException translated = this.holder.getPersistenceExceptionTranslator()
.translateExceptionIfPossible(p);
if (translated != null) {
throw translated;
}
}
throw p;
}
}
}
public void beforeCompletion() {
// Issue #18 Close SqlSession and deregister it now
// because afterCompletion may be called from a different thread
if (!this.holder.isOpen()) {
LOGGER
.debug(() -> "Transaction synchronization deregistering SqlSession [" + this.holder.getSqlSession() + "]");
TransactionSynchronizationManager.unbindResource(sessionFactory);
this.holderActive = false;
LOGGER.debug(() -> "Transaction synchronization closing SqlSession [" + this.holder.getSqlSession() + "]");
this.holder.getSqlSession().close();
}
}
在事务结束之前,需要将资源进行解绑,然后关闭会话。
public void afterCompletion(int status) {
if (this.holderActive) {
// afterCompletion may have been called from a different thread
// so avoid failing if there is nothing in this one
LOGGER
.debug(() -> "Transaction synchronization deregistering SqlSession [" + this.holder.getSqlSession() + "]");
TransactionSynchronizationManager.unbindResourceIfPossible(sessionFactory);
this.holderActive = false;
LOGGER.debug(() -> "Transaction synchronization closing SqlSession [" + this.holder.getSqlSession() + "]");
this.holder.getSqlSession().close();
}
this.holder.reset();
}
收尾工作。
为什么spring整合了mybatis之后能够解决线程安全问题
private static void registerSessionHolder(SqlSessionFactory sessionFactory, ExecutorType executorType,
PersistenceExceptionTranslator exceptionTranslator, SqlSession session) {
SqlSessionHolder holder;
// 如果spring开启了事务,那么这里将会被激活
if (TransactionSynchronizationManager.isSynchronizationActive()) {
Environment environment = sessionFactory.getConfiguration().getEnvironment();
if (environment.getTransactionFactory() instanceof SpringManagedTransactionFactory) {
LOGGER.debug(() -> "Registering transaction synchronization for SqlSession [" + session + "]");
// 将会话存起来
holder = new SqlSessionHolder(session, executorType, exceptionTranslator);
// 绑定资源到当前线程上
TransactionSynchronizationManager.bindResource(sessionFactory, holder);
TransactionSynchronizationManager
.registerSynchronization(new SqlSessionSynchronization(holder, sessionFactory));
// 设置当前线程同步资源为true
holder.setSynchronizedWithTransaction(true);
// 开始技术
holder.requested();
} else {
if (TransactionSynchronizationManager.getResource(environment.getDataSource()) == null) {
LOGGER.debug(() -> "SqlSession [" + session
+ "] was not registered for synchronization because DataSource is not transactional");
} else {
throw new TransientDataAccessResourceException(
"SqlSessionFactory must be using a SpringManagedTransactionFactory in order to use Spring transaction synchronization");
}
}
} else {
LOGGER.debug(() -> "SqlSession [" + session
+ "] was not registered for synchronization because synchronization is not active");
}
}
所以当来进行获取得到的时候getSqlSession#sessionHolder方法
// 从当前线程上获取得到对应的值
SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
private static SqlSession sessionHolder(ExecutorType executorType, SqlSessionHolder holder) {
SqlSession session = null;
// 事务已经激活!那么可以来进行获取
if (holder != null && holder.isSynchronizedWithTransaction()) {
if (holder.getExecutorType() != executorType) {
throw new TransientDataAccessResourceException(
"Cannot change the ExecutorType when there is an existing transaction");
}
holder.requested();
LOGGER.debug(() -> "Fetched SqlSession [" + holder.getSqlSession() + "] from current transaction");
session = holder.getSqlSession();
}
return session;
}
返回当前线程上的会话。
那么看下什么时候来进行提交的:
if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
// force commit even on non-dirty sessions because some databases require
// a commit/rollback before calling close()
sqlSession.commit(true);
}
看下具体方法:
public static boolean isSqlSessionTransactional(SqlSession session, SqlSessionFactory sessionFactory) {
notNull(session, NO_SQL_SESSION_SPECIFIED);
notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED);
// 当前线程是否和上下文中的线程是一致的
SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
return (holder != null) && (holder.getSqlSession() == session);
}
如果返回的是true,那么表示利用的是存在事务,先不提交。需要进行复用。
找了一下,这里的只负责一个线程的不断利用,但是销毁的方法存储在重写的同步器里面。
提交阶段:
public void beforeCommit(boolean readOnly) {
// Connection commit or rollback will be handled by ConnectionSynchronization or
// DataSourceTransactionManager.
// But, do cleanup the SqlSession / Executor, including flushing BATCH statements so
// they are actually executed.
// SpringManagedTransaction will no-op the commit over the jdbc connection
// TODO This updates 2nd level caches but the tx may be rolledback later on!
if (TransactionSynchronizationManager.isActualTransactionActive()) {
try {
LOGGER.debug(() -> "Transaction synchronization committing SqlSession [" + this.holder.getSqlSession() + "]");
this.holder.getSqlSession().commit();
} catch (PersistenceException p) {
if (this.holder.getPersistenceExceptionTranslator() != null) {
DataAccessException translated = this.holder.getPersistenceExceptionTranslator()
.translateExceptionIfPossible(p);
if (translated != null) {
throw translated;
}
}
throw p;
}
}
}
但是真正的提交和回滚操作却是交给spring来进行管理的,而不是sqlsession能够来进行管理的。
因为数据库连接是由spring创建出来的,因为让spring自己来进行决定是回滚还是提交事务!
事务完成之后阶段:
public void afterCompletion(int status) {
if (this.holderActive) {
// afterCompletion may have been called from a different thread
// so avoid failing if there is nothing in this one
LOGGER
.debug(() -> "Transaction synchronization deregistering SqlSession [" + this.holder.getSqlSession() + "]");
TransactionSynchronizationManager.unbindResourceIfPossible(sessionFactory);
this.holderActive = false;
LOGGER.debug(() -> "Transaction synchronization closing SqlSession [" + this.holder.getSqlSession() + "]");
this.holder.getSqlSession().close();
}
this.holder.reset();
}
才会真正的去关闭掉SqlSession
事务提交和回滚
对于事务提交和回滚来说,肯定都是利用conn来进行提交和回滚的。对于其他的操作方式来说,都不是真正意义上的提交和回滚操作。
提交和回滚的核心代码:
completeTransactionAfterThrowing(txInfo, ex);
.......
commitTransactionAfterReturning(txInfo);
这里的提交并非是真正意义上的提交,回滚也不是真正意义上的回滚代码。
提交
public final void commit(TransactionStatus status) throws TransactionException {
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;
// 当前事务中是否有局部回滚操作
if (defStatus.isLocalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Transactional code has requested rollback");
}
// 如果存在,那么需要进行回滚操作
processRollback(defStatus, false);
return;
}
// 是否设置了全局回滚,如果设置了都将会来进行回滚
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);
}
回滚
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
"] after exception: " + ex);
}
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;
}
}
}
}
如果代码逻辑中抛出的错误是指定的错误,那么将会在if中执行回滚操作;如果不在指定的异常中,那么将会在else中执行提交操作。
public final void rollback(TransactionStatus status) throws TransactionException {
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;
processRollback(defStatus, false);
}
看下面这行代码:
// Participating in larger transaction
if (status.hasTransaction()) {
// 如果是局部回滚或者是设置了全局失败就加入胡滚操作
if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
if (status.isDebug()) {
logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
}
// 添加回滚标记
doSetRollbackOnly(status);
}
else {
if (status.isDebug()) {
logger.debug("Participating transaction failed - letting transaction originator decide on rollback");
}
}
}
在事务传播中,这个是一个重要的标记。例子如下所示:
@Transactional
public A a(){
aop.b();
}
@Transactional
public B b(){
int i = 1/0;
return b;
}
这里造成的效果就是会将回滚标记设置为true
txObject.setRollbackOnly();
public void setRollbackOnly() {
this.rollbackOnly = true;
}
而这又是存在ConnectionHolder中的!相当于是几个事务公用的一个属性信息。能够让外部事务知道该进行回滚。
我们还可以手动的来进行设置这里的操作。
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
手动的来设置这里的回滚操作!
TransactionInfo的创建和销毁
事务信息,看下对应的创建过程
protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, String joinpointIdentification,
@Nullable TransactionStatus status) {
// 根据定义来创建事务对象
TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
if (txAttr != null) {
// We need a transaction for this method...
if (logger.isTraceEnabled()) {
logger.trace("Getting transaction for [" + txInfo.getJoinpointIdentification() + "]");
}
// The transaction manager will flag an error if an incompatible tx already exists.
txInfo.newTransactionStatus(status);
}
else {
// The TransactionInfo.hasTransaction() method will return false. We created it only
// to preserve the integrity of the ThreadLocal stack maintained in this class.
if (logger.isTraceEnabled()) {
logger.trace("No need to create transaction for [" + joinpointIdentification +
"]: This method is not transactional.");
}
}
// We always bind the TransactionInfo to the thread, even if we didn't create
// a new transaction here. This guarantees that the TransactionInfo stack
// will be managed correctly even if no transaction was created by this aspect.
txInfo.bindToThread();
return txInfo;
}
看下这里的一段代码:
private static final ThreadLocal<TransactionInfo> transactionInfoHolder =
new NamedThreadLocal<>("Current aspect-driven transaction");
private void bindToThread() {
// Expose current TransactionStatus, preserving any existing TransactionStatus
// for restoration after this transaction is complete.
this.oldTransactionInfo = transactionInfoHolder.get();
transactionInfoHolder.set(this);
}
将之前的旧的事务信息保存到当前事务属性oldTransactionInfo中来,然后将当前的事务信息作为线程即将使用的。
在当前的事务执行完成之后,下面开始来执行恢复信息:
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);
}
看下清理事务信息
protected void cleanupTransactionInfo(@Nullable TransactionInfo txInfo) {
if (txInfo != null) {
txInfo.restoreThreadLocalStatus();
}
}
private void restoreThreadLocalStatus() {
// Use stack to restore old transaction TransactionInfo.
// Will be null if none was set.
transactionInfoHolder.set(this.oldTransactionInfo);
}
将存入的就的事务信息回填到当前线程中来。
TransactionStatus的创建和销毁
创建
TransactionStatus status = null;
if (txAttr != null) {
if (tm != null) {
status = tm.getTransaction(txAttr);
根据事务属性配置信息得到属性状态
来到startTransaction方法中来:
DefaultTransactionStatus status = newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
看下具体的创建过程:
/**
* Create a TransactionStatus instance for the given arguments.
*/
// newTransaction默认是true,表示的是新事务
// 但是对于是否是新同步来说,需要来进行判断!如果当前没有,那么这个事务才会有
protected DefaultTransactionStatus newTransactionStatus(
TransactionDefinition definition, @Nullable Object transaction, boolean newTransaction,
boolean newSynchronization, boolean debug, @Nullable Object suspendedResources) {
boolean actualNewSynchronization = newSynchronization &&
!TransactionSynchronizationManager.isSynchronizationActive();
return new DefaultTransactionStatus(
transaction, newTransaction, actualNewSynchronization,
definition.isReadOnly(), debug, suspendedResources);
}
public DefaultTransactionStatus(
@Nullable Object transaction, boolean newTransaction, boolean newSynchronization,
boolean readOnly, boolean debug, @Nullable Object suspendedResources) {
// 这里的事务是ConnectionHodler
this.transaction = transaction;
// 通过计算得来的
this.newTransaction = newTransaction;
//
this.newSynchronization = newSynchronization;
this.readOnly = readOnly;
this.debug = debug;
this.suspendedResources = suspendedResources;
}
根据指定的参数信息来创建对应的事务状态。
事务状态包含了:
- 1、事务
- 2、是否是新的事务
- 3、是否有事务同步信息
- 4、是否只读
- 5、挂起的事务资源信息
只有是新的同步的时候,才会将同步资源绑定到当前线程中来。
销毁
在事务提交或者是销毁阶段都会来做处理
在cleanupAfterCompletion(status);方法中来进行处理
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());
}
}
看下具体的清理过程:
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()) {
if (logger.isDebugEnabled()) {
logger.debug("Releasing JDBC Connection [" + con + "] after transaction");
}
DataSourceUtils.releaseConnection(con, this.dataSource);
}
txObject.getConnectionHolder().clear();
}
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<TransactionSynchronization> suspendedSynchronizations = resourcesHolder.suspendedSynchronizations;
if (suspendedSynchronizations != null) {
// 设置事务的激活状态等等
TransactionSynchronizationManager.setActualTransactionActive(resourcesHolder.wasActive);等等
TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(resourcesHolder.isolationLevel);
TransactionSynchronizationManager.setCurrentTransactionReadOnly(resourcesHolder.readOnly);
TransactionSynchronizationManager.setCurrentTransactionName(resourcesHolder.name);
doResumeSynchronization(suspendedSynchronizations);
}
}
}
看一下恢复中做的操作:
private void doResumeSynchronization(List<TransactionSynchronization> suspendedSynchronizations) {
// 首先会来进行初始化操作
TransactionSynchronizationManager.initSynchronization();
for (TransactionSynchronization synchronization : suspendedSynchronizations) {
// 会来调用每个同步方法。用户自定义操作
synchronization.resume();
// 然后重新进行注册
TransactionSynchronizationManager.registerSynchronization(synchronization);
}
}
资源挂起和恢复
在事务进行状态中,如果存在着事务,那么需要将事务进行挂起
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
return handleExistingTransaction(def, transaction, debugEnabled);
}
判断存在事务的依据是:
protected boolean isExistingTransaction(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
// 存在着数据库连接且数据库连接中的事务已经被激活
return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());
}
那么就开始来处理已经存在的事务:根据传播行为来进行确定
/**
* Create a TransactionStatus for an existing transaction.
*/
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) {
if (debugEnabled) {
logger.debug("Suspending current transaction");
}
Object suspendedResources = suspend(transaction);
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
if (debugEnabled) {
logger.debug("Suspending current transaction, creating new transaction with name [" +
definition.getName() + "]");
}
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 (!isNestedTransactionAllowed()) {
throw new NestedTransactionNotSupportedException(
"Transaction manager does not allow nested transactions by default - " +
"specify 'nestedTransactionAllowed' property with value 'true'");
}
if (debugEnabled) {
logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
}
if (useSavepointForNestedTransaction()) {
// Create savepoint within existing Spring-managed transaction,
// through the SavepointManager API implemented by TransactionStatus.
// Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.
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);
}
}
// Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.
if (debugEnabled) {
logger.debug("Participating in existing transaction");
}
if (isValidateExistingTransaction()) {
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {
Constants isoConstants = DefaultTransactionDefinition.constants;
throw new IllegalTransactionStateException("Participating transaction with definition [" +
definition + "] specifies isolation level which is incompatible with existing transaction: " +
(currentIsolationLevel != null ?
isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) :
"(unknown)"));
}
}
if (!definition.isReadOnly()) {
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
throw new IllegalTransactionStateException("Participating transaction with definition [" +
definition + "] is not marked as read-only but existing transaction is");
}
}
}
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}
那么看一下挂起资源是怎么进行挂起的:
SuspendedResourcesHolder suspendedResources = suspend(transaction);
具体的代码如下:
protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
// 存在着同步器
if (TransactionSynchronizationManager.isSynchronizationActive()) {
// 将存在的同步器保存,并将当前线程中的同步器全部清理掉
List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
try {
Object suspendedResources = null;
// 对DataSourceTransactionObject中的属性进行操作
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);
// 将当前线程中的同步器进行保存到SuspendedResourcesHolder中来
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;
}
}
然后将挂起的资源保存到DefaultTransactionStatus中来,在TransactionStatu进行销毁的时候会将其保存起来。