具有价值的网站建设平台,天津品牌网站建设好处,做阿里巴巴网站的电话号码,石家庄小学网站建设正文
上一篇文章我们讲解了事务的Advisor是如何注册进Spring容器的#xff0c;也讲解了Spring是如何将有配置事务的类配置上事务的#xff0c;实际上也就是用了AOP那一套#xff0c;也讲解了Advisor#xff0c;pointcut验证流程#xff0c;至此#xff0c;事务的初始化工…正文
上一篇文章我们讲解了事务的Advisor是如何注册进Spring容器的也讲解了Spring是如何将有配置事务的类配置上事务的实际上也就是用了AOP那一套也讲解了Advisorpointcut验证流程至此事务的初始化工作都已经完成了在之后的调用过程如果代理类的方法被调用都会调用BeanFactoryTransactionAttributeSourceAdvisor这个Advisor的增强方法也就是我们还未提到的那个Advisor里面的advise还记得吗在自定义标签的时候我们将TransactionInterceptor这个Advice作为bean注册进IOC容器并且将其注入进Advisor中这个Advice在代理类的invoke方法中会被封装到拦截器链中最终事务的功能都在advise中体现所以我们先来关注一下TransactionInterceptor这个类吧。最全面的Java面试网站
TransactionInterceptor类继承自MethodInterceptor所以调用该类是从其invoke方法开始的首先预览下这个方法
Override
Nullable
public Object invoke(final MethodInvocation invocation) throws Throwable {// Work out the target class: may be {code null}.// The TransactionAttributeSource should be passed the target class// as well as the method, which may be from an interface.Class? targetClass (invocation.getThis() ! null ? AopUtils.getTargetClass(invocation.getThis()) : null);// Adapt to TransactionAspectSupports invokeWithinTransaction...return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}重点来了进入invokeWithinTransaction方法
Nullable
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);// 获取beanFactory中的transactionManagerfinal PlatformTransactionManager tm determineTransactionManager(txAttr);// 构造方法唯一标识类.方法如service.UserServiceImpl.savefinal String joinpointIdentification methodIdentification(method, targetClass, txAttr);// 声明式事务处理if (txAttr null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {// 创建TransactionInfoTransactionInfo txInfo createTransactionIfNecessary(tm, txAttr, joinpointIdentification);Object retVal null;try {// 执行原方法// 继续调用方法拦截器链,这里一般将会调用目标类的方法,如:AccountServiceImpl.save方法retVal invocation.proceedWithInvocation();}catch (Throwable ex) {// 异常回滚completeTransactionAfterThrowing(txInfo, ex);// 手动向上抛出异常则下面的提交事务不会执行// 如果子事务出异常则外层事务代码需catch住子事务代码不然外层事务也会回滚throw ex;}finally {// 消除信息cleanupTransactionInfo(txInfo);}// 提交事务commitTransactionAfterReturning(txInfo);return retVal;}else {final ThrowableHolder throwableHolder new ThrowableHolder();try {// 编程式事务处理Object result ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, status - {TransactionInfo txInfo prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);try {return invocation.proceedWithInvocation();}catch (Throwable ex) {if (txAttr.rollbackOn(ex)) {// A RuntimeException: will lead to a rollback.if (ex instanceof RuntimeException) {throw (RuntimeException) ex;}else {throw new ThrowableHolderException(ex);}}else {// A normal return value: will lead to a commit.throwableHolder.throwable ex;return null;}}finally {cleanupTransactionInfo(txInfo);}});// Check result state: It might indicate a Throwable to rethrow.if (throwableHolder.throwable ! null) {throw throwableHolder.throwable;}return result;}catch (ThrowableHolderException ex) {throw ex.getCause();}catch (TransactionSystemException ex2) {if (throwableHolder.throwable ! null) {logger.error(Application exception overridden by commit exception, throwableHolder.throwable);ex2.initApplicationException(throwableHolder.throwable);}throw ex2;}catch (Throwable ex2) {if (throwableHolder.throwable ! null) {logger.error(Application exception overridden by commit exception, throwableHolder.throwable);}throw ex2;}}
}创建事务Info对象
我们先分析事务创建的过程。
protected TransactionInfo createTransactionIfNecessary(Nullable PlatformTransactionManager tm,Nullable TransactionAttribute txAttr, final String joinpointIdentification) {// If no name specified, apply method identification as transaction name.// 如果没有名称指定则使用方法唯一标识并使用DelegatingTransactionAttribute封装txAttrif (txAttr ! null txAttr.getName() null) {txAttr new DelegatingTransactionAttribute(txAttr) {Overridepublic String getName() {return joinpointIdentification;}};}TransactionStatus status null;if (txAttr ! null) {if (tm ! null) {// 获取TransactionStatusstatus tm.getTransaction(txAttr);}else {if (logger.isDebugEnabled()) {logger.debug(Skipping transactional joinpoint [ joinpointIdentification ] because no transaction manager has been configured);}}}// 根据指定的属性与status准备一个TransactionInforeturn prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}对于createTransactionlfNecessary函数主要做了这样几件事情。
1使用 DelegatingTransactionAttribute 封装传入的 TransactionAttribute 实例。
对于传入的TransactionAttribute类型的参数txAttr当前的实际类型是RuleBasedTransactionAttribute是由获取事务属性时生成主要用于数据承载而这里之所以使用DelegatingTransactionAttribute进行封装当然是提供了更多的功能。
2获取事务。
事务处理当然是以事务为核心那么获取事务就是最重要的事情。
3构建事务信息。
根据之前几个步骤获取的信息构建Transactionlnfo并返回。 分享一份大彬精心整理的大厂面试手册包含计算机基础、Java基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等高频面试题非常实用有小伙伴靠着这份手册拿过字节offer~ 需要的小伙伴可以自行下载 http://mp.weixin.qq.com/s?__bizMzg2OTY1NzY0MQmid2247485445idx1sn1c6e224b9bb3da457f5ee03894493dbcchksmce98f543f9ef7c55325e3bf336607a370935a6c78dbb68cf86e59f5d68f4c51d175365a189f8#rd 获取事务
其中核心是在getTransaction方法中
Override
public final TransactionStatus getTransaction(Nullable TransactionDefinition definition) throws TransactionException {// 获取一个transactionObject transaction doGetTransaction();boolean debugEnabled logger.isDebugEnabled();if (definition null) {definition new DefaultTransactionDefinition();}// 如果在这之前已经存在事务了就进入存在事务的方法中if (isExistingTransaction(transaction)) {return handleExistingTransaction(definition, transaction, debugEnabled);}// 事务超时设置验证if (definition.getTimeout() TransactionDefinition.TIMEOUT_DEFAULT) {throw new InvalidTimeoutException(Invalid transaction timeout, definition.getTimeout());}// 走到这里说明此时没有存在事务如果传播特性是MANDATORY时抛出异常if (definition.getPropagationBehavior() TransactionDefinition.PROPAGATION_MANDATORY) {throw new IllegalTransactionStateException(No existing transaction found for transaction marked with propagation mandatory);}// 如果此时不存在事务当传播特性是REQUIRED或NEW或NESTED都会进入if语句块else if (definition.getPropagationBehavior() TransactionDefinition.PROPAGATION_REQUIRED ||definition.getPropagationBehavior() TransactionDefinition.PROPAGATION_REQUIRES_NEW ||definition.getPropagationBehavior() TransactionDefinition.PROPAGATION_NESTED) {// PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED都需要新建事务// 因为此时不存在事务将null挂起SuspendedResourcesHolder suspendedResources suspend(null);if (debugEnabled) {logger.debug(Creating new transaction with name [ definition.getName() ]: definition);}try {boolean newSynchronization (getTransactionSynchronization() ! SYNCHRONIZATION_NEVER);// new一个status存放刚刚创建的transaction然后将其标记为新事务// 这里transaction后面一个参数决定是否是新事务DefaultTransactionStatus status newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);// 新开一个连接的地方非常重要doBegin(transaction, definition);prepareSynchronization(status, definition);return status;}catch (RuntimeException | Error ex) {resume(null, suspendedResources);throw ex;}}else {// Create empty transaction: no actual transaction, but potentially synchronization.if (definition.getIsolationLevel() ! TransactionDefinition.ISOLATION_DEFAULT logger.isWarnEnabled()) {logger.warn(Custom isolation level specified but no actual transaction initiated; isolation level will effectively be ignored: definition);}// 其他的传播特性一律返回一个空事务transaction null//当前不存在事务且传播机制PROPAGATION_SUPPORTS/PROPAGATION_NOT_SUPPORTED/PROPAGATION_NEVER这三种情况创建“空”事务boolean newSynchronization (getTransactionSynchronization() SYNCHRONIZATION_ALWAYS);return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);}
}先来看看transaction是如何被创建出来的
Override
protected Object doGetTransaction() {// 这里DataSourceTransactionObject是事务管理器的一个内部类// DataSourceTransactionObject就是一个transaction这里new了一个出来DataSourceTransactionObject txObject new DataSourceTransactionObject();txObject.setSavepointAllowed(isNestedTransactionAllowed());// 解绑与绑定的作用在此时体现如果当前线程有绑定的话将会取出holder// 第一次conHolder肯定是nullConnectionHolder conHolder (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());// 此时的holder被标记成一个旧holdertxObject.setConnectionHolder(conHolder, false);return txObject;
}创建transaction过程很简单接着就会判断当前是否存在事务
Override
protected boolean isExistingTransaction(Object transaction) {DataSourceTransactionObject txObject (DataSourceTransactionObject) transaction;return (txObject.hasConnectionHolder() txObject.getConnectionHolder().isTransactionActive());
}public boolean hasConnectionHolder() {return (this.connectionHolder ! null);
}这里判断是否存在事务的依据主要是获取holder中的transactionActive变量是否为true如果是第一次进入事务holder直接为null判断不存在了如果是第二次进入事务transactionActive变量是为true的后面会提到是在哪里把它变成true的由此来判断当前是否已经存在事务了。
至此源码分成了2条处理线
1.当前已存在事务isExistingTransaction()判断是否存在事务存在事务handleExistingTransaction()根据不同传播机制不同处理
2.当前不存在事务: 不同传播机制不同处理
当前不存在事务
如果不存在事务传播特性又是REQUIRED或NEW或NESTED将会先挂起null这个挂起方法我们后面再讲然后创建一个DefaultTransactionStatus 并将其标记为新事务然后执行doBegin(transaction, definition);这个方法也是一个关键方法
神秘又关键的status对象
TransactionStatus接口
public interface TransactionStatus extends SavepointManager, Flushable {// 返回当前事务是否为新事务否则将参与到现有事务中或者可能一开始就不在实际事务中运行boolean isNewTransaction();// 返回该事务是否在内部携带保存点也就是说已经创建为基于保存点的嵌套事务。boolean hasSavepoint();// 设置事务仅回滚。void setRollbackOnly();// 返回事务是否已标记为仅回滚boolean isRollbackOnly();// 将会话刷新到数据存储区Overridevoid flush();// 返回事物是否已经完成无论提交或者回滚。boolean isCompleted();
}再来看看实现类DefaultTransactionStatus
DefaultTransactionStatus
public class DefaultTransactionStatus extends AbstractTransactionStatus {//事务对象Nullableprivate final Object transaction;//事务对象private final boolean newTransaction;private final boolean newSynchronization;private final boolean readOnly;private final boolean debug;//事务对象Nullableprivate final Object suspendedResources;public DefaultTransactionStatus(Nullable Object transaction, boolean newTransaction, boolean newSynchronization,boolean readOnly, boolean debug, Nullable Object suspendedResources) {this.transaction transaction;this.newTransaction newTransaction;this.newSynchronization newSynchronization;this.readOnly readOnly;this.debug debug;this.suspendedResources suspendedResources;}//略...
}我们看看这行代码 DefaultTransactionStatus status newTransactionStatus( definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
// 这里是构造一个status对象的方法
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);
}实际上就是封装了事务属性definition新创建的**transaction**并且将事务状态属性设置为新事务最后一个参数为被挂起的事务。
简单了解一下关键参数即可
第二个参数transaction事务对象在一开头就有创建其就是事务管理器的一个内部类。
第三个参数newTransaction布尔值一个标识用于判断是否是新的事务用于提交或者回滚方法中是新的才会提交或者回滚。
最后一个参数suspendedResources被挂起的对象资源挂起操作会返回旧的holder将其与一些事务属性一起封装成一个对象就是这个suspendedResources这个对象了它会放在status中在最后的清理工作方法中判断status中是否有这个挂起对象如果有会恢复它
接着我们来看看关键代码 doBegin(transaction, definition); Overrideprotected void doBegin(Object transaction, TransactionDefinition definition) {DataSourceTransactionObject txObject (DataSourceTransactionObject) transaction;Connection con null;try {// 判断如果transaction没有holder的话才去从dataSource中获取一个新连接if (!txObject.hasConnectionHolder() ||txObject.getConnectionHolder().isSynchronizedWithTransaction()) {//通过dataSource获取连接Connection newCon this.dataSource.getConnection();if (logger.isDebugEnabled()) {logger.debug(Acquired Connection [ newCon ] for JDBC transaction);}// 所以只有transaction中的holder为空时才会设置为新holder// 将获取的连接封装进ConnectionHolder然后封装进transaction的connectionHolder属性txObject.setConnectionHolder(new ConnectionHolder(newCon), true);}//设置新的连接为事务同步中txObject.getConnectionHolder().setSynchronizedWithTransaction(true);con txObject.getConnectionHolder().getConnection();//conn设置事务隔离级别,只读Integer previousIsolationLevel DataSourceUtils.prepareConnectionForTransaction(con, definition);txObject.setPreviousIsolationLevel(previousIsolationLevel);//DataSourceTransactionObject设置事务隔离级别// 如果是自动提交切换到手动提交if (con.getAutoCommit()) {txObject.setMustRestoreAutoCommit(true);if (logger.isDebugEnabled()) {logger.debug(Switching JDBC Connection [ con ] to manual commit);}con.setAutoCommit(false);}// 如果只读执行sql设置事务只读prepareTransactionalConnection(con, definition);// 设置connection持有者的事务开启状态txObject.getConnectionHolder().setTransactionActive(true);int timeout determineTimeout(definition);if (timeout ! TransactionDefinition.TIMEOUT_DEFAULT) {// 设置超时秒数txObject.getConnectionHolder().setTimeoutInSeconds(timeout);}// 将当前获取到的连接绑定到当前线程if (txObject.isNewConnectionHolder()) {TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());}}catch (Throwable ex) {if (txObject.isNewConnectionHolder()) {DataSourceUtils.releaseConnection(con, this.dataSource);txObject.setConnectionHolder(null, false);}throw new CannotCreateTransactionException(Could not open JDBC Connection for transaction, ex);}}conn设置事务隔离级别
Nullable
public static Integer prepareConnectionForTransaction(Connection con, Nullable TransactionDefinition definition)throws SQLException {Assert.notNull(con, No Connection specified);// Set read-only flag.// 设置数据连接的只读标识if (definition ! null definition.isReadOnly()) {try {if (logger.isDebugEnabled()) {logger.debug(Setting JDBC Connection [ con ] read-only);}con.setReadOnly(true);}catch (SQLException | RuntimeException ex) {Throwable exToCheck ex;while (exToCheck ! null) {if (exToCheck.getClass().getSimpleName().contains(Timeout)) {// Assume its a connection timeout that would otherwise get lost: e.g. from JDBC 4.0throw ex;}exToCheck exToCheck.getCause();}// read-only not supported SQLException - ignore, its just a hint anywaylogger.debug(Could not set JDBC Connection read-only, ex);}}// Apply specific isolation level, if any.// 设置数据库连接的隔离级别Integer previousIsolationLevel null;if (definition ! null definition.getIsolationLevel() ! TransactionDefinition.ISOLATION_DEFAULT) {if (logger.isDebugEnabled()) {logger.debug(Changing isolation level of JDBC Connection [ con ] to definition.getIsolationLevel());}int currentIsolation con.getTransactionIsolation();if (currentIsolation ! definition.getIsolationLevel()) {previousIsolationLevel currentIsolation;con.setTransactionIsolation(definition.getIsolationLevel());}}return previousIsolationLevel;
}我们看到都是通过 Connection 去设置
线程变量的绑定
我们看 doBegin 方法的47行**将当前获取到的连接绑定到当前线程绑定与解绑围绕一个线程变量此变量在TransactionSynchronizationManager**类中
private static final ThreadLocalMapObject, Object resources new NamedThreadLocal(Transactional resources);这是一个 static final 修饰的 线程变量存储的是一个Map我们来看看47行的静态方法bindResource
public static void bindResource(Object key, Object value) throws IllegalStateException {// 从上面可知线程变量是一个Map而这个Key就是dataSource// 这个value就是holderObject actualKey TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);Assert.notNull(value, Value must not be null);// 获取这个线程变量MapMapObject, Object map resources.get();// set ThreadLocal Map if none foundif (map null) {map new HashMap();resources.set(map);}// 将新的holder作为valuedataSource作为key放入当前线程Map中Object oldValue map.put(actualKey, value);// Transparently suppress a ResourceHolder that was marked as void...if (oldValue instanceof ResourceHolder ((ResourceHolder) oldValue).isVoid()) {oldValue null;}if (oldValue ! null) {throw new IllegalStateException(Already value [ oldValue ] for key [ actualKey ] bound to thread [ Thread.currentThread().getName() ]);} Thread.currentThread().getName() ]);}// 略...
}扩充知识点
这里再扩充一点mybatis中获取的数据库连接就是根据 dataSource 从ThreadLocal中获取的
以查询举例会调用Executor#doQuery方法 最终会调用DataSourceUtils#doGetConnection获取真正的数据库连接其中TransactionSynchronizationManager中保存的就是方法调用前spring增强方法中绑定到线程的connection从而保证整个事务过程中connection的一致性 我们看看TransactionSynchronizationManager.getResource(Object key)这个方法
Nullable
public static Object getResource(Object key) {Object actualKey TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);Object value doGetResource(actualKey);if (value ! null logger.isTraceEnabled()) {logger.trace(Retrieved value [ value ] for key [ actualKey ] bound to thread [ Thread.currentThread().getName() ]);}return value;
}Nullable
private static Object doGetResource(Object actualKey) {MapObject, Object map resources.get();if (map null) {return null;}Object value map.get(actualKey);// Transparently remove ResourceHolder that was marked as void...if (value instanceof ResourceHolder ((ResourceHolder) value).isVoid()) {map.remove(actualKey);// Remove entire ThreadLocal if empty...if (map.isEmpty()) {resources.remove();}value null;}return value;
}就是从线程变量的Map中根据 DataSource获取 ConnectionHolder
已经存在的事务
前面已经提到第一次事务开始时必会新创一个holder然后做绑定操作此时线程变量是有holder的且avtive为true如果第二个事务进来去new一个transaction之后去线程变量中取holderholder是不为空的且active是为true的所以会进入handleExistingTransaction方法 private TransactionStatus handleExistingTransaction(TransactionDefinition definition, Object transaction, boolean debugEnabled)throws TransactionException {// 1.NERVER不支持当前事务;如果当前事务存在抛出异常报错if (definition.getPropagationBehavior() TransactionDefinition.PROPAGATION_NEVER) {throw new IllegalTransactionStateException(Existing transaction found for transaction marked with propagation never);}// 2.NOT_SUPPORTED不支持当前事务现有同步将被挂起挂起当前事务,返回一个空事务if (definition.getPropagationBehavior() TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {if (debugEnabled) {logger.debug(Suspending current transaction);}// 这里会将原来的事务挂起,并返回被挂起的对象Object suspendedResources suspend(transaction);boolean newSynchronization (getTransactionSynchronization() SYNCHRONIZATION_ALWAYS);// 这里可以看到第二个参数transaction传了一个空事务第三个参数false为旧标记// 最后一个参数就是将前面挂起的对象封装进新的Status中当前事务执行完后就恢复suspendedResourcesreturn prepareTransactionStatus(definition, null, false, newSynchronization, debugEnabled, suspendedResources);}// 3.REQUIRES_NEW挂起当前事务创建新事务if (definition.getPropagationBehavior() TransactionDefinition.PROPAGATION_REQUIRES_NEW) {if (debugEnabled) {logger.debug(Suspending current transaction, creating new transaction with name [ definition.getName() ]);}// 将原事务挂起此时新建事务不与原事务有关系// 会将transaction中的holder设置为null然后解绑SuspendedResourcesHolder suspendedResources suspend(transaction);try {boolean newSynchronization (getTransactionSynchronization() ! SYNCHRONIZATION_NEVER);// new一个status出来传入transaction并且为新事务标记然后传入挂起事务DefaultTransactionStatus status newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);// 这里也做了一次doBegin此时的transaction中holer是为空的因为之前的事务被挂起了// 所以这里会取一次新的连接并且绑定doBegin(transaction, definition);prepareSynchronization(status, definition);return status;}catch (RuntimeException beginEx) {resumeAfterBeginException(transaction, suspendedResources, beginEx);throw beginEx;}catch (Error beginErr) {resumeAfterBeginException(transaction, suspendedResources, beginErr);throw beginErr;}}// 如果此时的传播特性是NESTED不会挂起事务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() ]);}// 这里如果是JTA事务管理器就不可以用savePoint了将不会进入此方法if (useSavepointForNestedTransaction()) { // 这里不会挂起事务说明NESTED的特性是原事务的子事务而已// new一个status传入transaction传入旧事务标记传入挂起对象nullDefaultTransactionStatus status prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);// 这里是NESTED特性特殊的地方在先前存在事务的情况下会建立一个savePointstatus.createAndHoldSavepoint();return status;}else {// JTA事务走这个分支创建新事务boolean newSynchronization (getTransactionSynchronization() ! SYNCHRONIZATION_NEVER);DefaultTransactionStatus status newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, null);doBegin(transaction, definition);prepareSynchronization(status, definition);return status;}}// 到这里PROPAGATION_SUPPORTS 或 PROPAGATION_REQUIRED或PROPAGATION_MANDATORY存在事务加入事务即可标记为旧事务空挂起boolean newSynchronization (getTransactionSynchronization() ! SYNCHRONIZATION_NEVER);return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);}对于已经存在事务的处理过程中我们看到了很多熟悉的操作但是也有些不同的地方函数中对已经存在的事务处理考虑两种情况。
1PROPAGATION_REQUIRES_NEW表示当前方法必须在它自己的事务里运行一个新的事务将被启动而如果有一个事务正在运行的话则在这个方法运行期间被挂起。而Spring中对于此种传播方式的处理与新事务建立最大的不同点在于使用suspend方法将原事务挂起。 将信息挂起的目的当然是为了在当前事务执行完毕后在将原事务还原。
2PROPAGATION_NESTED表示如果当前正有一个事务在运行中则该方法应该运行在一个嵌套的事务中被嵌套的事务可以独立于封装事务进行提交或者回滚如果封装事务不存在行为就像PROPAGATION_REQUIRES_NEW。对于嵌入式事务的处理Spring中主要考虑了两种方式的处理。
Spring中允许嵌入事务的时候则首选设置保存点的方式作为异常处理的回滚。对于其他方式比如JTA无法使用保存点的方式那么处理方式与PROPAGATION_ REQUIRES_NEW相同而一旦出现异常则由Spring的事务异常处理机制去完成后续操作。
对于挂起操作的主要目的是记录原有事务的状态以便于后续操作对事务的恢复
小结
到这里我们可以知道在当前存在事务的情况下根据传播特性去决定是否为新事务是否挂起当前事务。
NOT_SUPPORTED 会挂起事务不运行doBegin方法传空transaction标记为旧事务。封装status对象
return prepareTransactionStatus(definition, null, false, newSynchronization, debugEnabled, suspendedResources)REQUIRES_NEW 将会挂起事务且运行doBegin方法标记为新事务。封装status对象
DefaultTransactionStatus status newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);NESTED 不会挂起事务且不会运行doBegin方法标记为旧事务但会创建savePoint。封装status对象
DefaultTransactionStatus status prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);其他事务例如REQUIRED 不会挂起事务封装原有的transaction不会运行doBegin方法标记旧事务封装status对象
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);挂起
对于挂起操作的主要目的是记录原有事务的状态以便于后续操作对事务的恢复
Nullable
protected final SuspendedResourcesHolder suspend(Nullable Object transaction) throws TransactionException {if (TransactionSynchronizationManager.isSynchronizationActive()) {ListTransactionSynchronization suspendedSynchronizations doSuspendSynchronization();try {Object suspendedResources null;if (transaction ! null) {// 这里是真正做挂起的方法这里返回的是一个holdersuspendedResources 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);// 将事务各个属性与挂起的holder一并封装进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;}
}Override
protected Object doSuspend(Object transaction) {DataSourceTransactionObject txObject (DataSourceTransactionObject) transaction;// 将transaction中的holder属性设置为空txObject.setConnectionHolder(null);// ConnnectionHolder从线程变量中解绑return TransactionSynchronizationManager.unbindResource(obtainDataSource());
}我们来看看 unbindResource
private static Object doUnbindResource(Object actualKey) {// 取得当前线程的线程变量MapMapObject, Object map resources.get();if (map null) {return null;}// 将key为dataSourece的value移除出Map然后将旧的Holder返回Object value map.remove(actualKey);// Remove entire ThreadLocal if empty...// 如果此时map为空直接清除线程变量if (map.isEmpty()) {resources.remove();}// Transparently suppress a ResourceHolder that was marked as void...if (value instanceof ResourceHolder ((ResourceHolder) value).isVoid()) {value null;}if (value ! null logger.isTraceEnabled()) {logger.trace(Removed value [ value ] for key [ actualKey ] from thread [ Thread.currentThread().getName() ]);}// 将旧Holder返回return value;
}可以回头看一下解绑操作的介绍。这里挂起主要干了三件事
将transaction中的holder属性设置为空解绑会返回线程中的那个旧的holder出来从而封装到SuspendedResourcesHolder对象中将SuspendedResourcesHolder放入status中方便后期子事务完成后恢复外层事务
最后给大家分享一个Github仓库上面有大彬整理的300多本经典的计算机书籍PDF包括C语言、C、Java、Python、前端、数据库、操作系统、计算机网络、数据结构和算法、机器学习、编程人生等可以star一下下次找书直接在上面搜索仓库持续更新中~ Github地址
如果访问不了Github可以访问码云地址。
码云地址