说起spring事务大家肯定都不陌生,在springboot项目中我们只需在需要事务控制的方法上面添加@Transactional注解即可,但是在springboot项目中使用事务,如下俩个注解不加也行。
spring事务:
@EnableTransactionManagement为我们的项目开启了spring事务,点进去
点进去发现TransactionManagementConfigurationSelector是一个importSelector,为ioc容器中注册了俩个bean (此处涉及到@import注解的知识)
点进去AutoProxyRegistrar最终会发现,里面的注册逻辑和@EnableAspectJAutoProxy注解注册入口类的逻辑是一模一样,我们暂时只需要知道AutoProxyRegistrar为我们注册了一个入口类即可
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
/**
* AUTO_PROXY_CREATOR_BEAN_NAME:internalAutoProxyCreator
*/
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
/**
* 容器中存在的入口类
*/
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
/**
* cls:当前要注册的入口类
* AnnotationAwareAspectJAutoProxyCreator优先级最高
* requiredPriority:当前要注册入口类的优先级
*/
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
/**
* 注册当前传进来的入口类
*/
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
ProxyTransactionManagementConfiguration点进去,发现此类帮我们注册了三个bean (这些bean的调用涉及到aop调用流程相关知识点)
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
/**
* 给容器中注册了一个bean:BeanFactoryTransactionAttributeSourceAdvisor
*/
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
/**
*生成一个事务的切面
*/
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
/**
* 搜集@Transaction:注解上面的所有属性
*/
advisor.setTransactionAttributeSource(transactionAttributeSource);
/**
* 设置事务通知,涉及到aop调用链
*/
advisor.setAdvice(transactionInterceptor);
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
}
return advisor;
}
/**
* 搜集@Transaction:注解上面的所有属性
*/
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
/**
* 设置事务通知,涉及到aop调用链
*/
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource);
/**
* 事务管理器
*/
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
小结@EnableTransactionManagement
EnableTransactionManagement核心功能在于:给ioc注册了一个事务切面(advisor),切面中织入了通知(@Transactional),在每次调用事务方法之前会进行对事务的操作,继而才是执行目标方法。
不着急分析源码先来写一个小案例感受一下spring事务吧
@Service
public class UserServiceImpl implements UserService {
@Autowired
UserServiceImpl userService;
@Transactional(propagation = Propagation.NEW)
public void a() {
this.update(new UpdateWrapper<User>().eq("id", 52).set("age", 100));
System.out.println("a事务更新完毕");
userService.b();
userService.c();
userService.d();
}
}
上述的 UserServiceImpl 就是一个事务切面 ,其中的b()、c()、d()方法上都标注了@Transactional(propagation = Propagation.NEW) 注解,且方法里面依次更新 id 为53、54、55这些行的数据 并set age = 100。
编写测试类,当我们启动项目的时候访问我们的UserController中的test()接口继而触发 userService.a(); 就会依次执行更新操作,id从52 - 55的行数据的age 都会为100。
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
UserServiceImpl userService;
@GetMapping("/test")
public String test() {
userService.a();
return "ok";
}
那如果我们在事务c这里抛出一个异常,其他事务依旧是原样的,执行的结果又会是怎么样呢?结果就是b更新成功,a、c、d更新失败。
反正b、c、d方法都是同一个类下面的,我这样调用行不行呢?答案是肯定不行!这样调用b、c、d上面的@Transactional注解都会失效。b、c、d都没有走UserServiceImpl这个事务切面,事务都会失效。
直接从此处断点,点进去发现和aop的执行流程一模一样。搞懂了aop的运行流程,对于搞懂事务的运行流程还是很轻松的。只是可能事务里面的逻辑大家还是不是很清楚而已。
userService.a() 的执行会来到这里,在调用a()中的逻辑前,会先拿到接着遍历代理对象中的拦截器链
果然还是熟悉的代码呀,挨个遍历调用拦截器中的invoke()方法,换言之就是执行a()前会先执行事务切面中的事务通知逻辑
接着点进invoke()方法就是我们的spring事务的调用源码了。
我直接一句好家伙,这一团密密麻麻的是个什么鬼东西,这个是我用maven依赖debug时的spring最新的源码,我以下贴的带注释的源码是基于spring 5.0源码来分析的。原理都一样spring5.0源码我自己写了注释,最新的没有克隆编译写注释
spring 5.0 中的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.
/**
* 获取@Transaction注解上的源属性
*/
TransactionAttributeSource tas = getTransactionAttributeSource();
/**
* tas理论上和txAttr差不多
*/
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
/**
* 获取事务管理器
*/
final TransactionManager tm = determineTransactionManager(txAttr);
/**
* TODO
*/
if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
boolean isSuspendingFunction = KotlinDetector.isSuspendingFunction(method);
boolean hasSuspendingFlowReturnType = isSuspendingFunction &&
COROUTINES_FLOW_CLASS_NAME.equals(new MethodParameter(method, -1).getParameterType().getName());
if (isSuspendingFunction && !(invocation instanceof CoroutinesInvocationCallback)) {
throw new IllegalStateException("Coroutines invocation not supported: " + method);
}
CoroutinesInvocationCallback corInv = (isSuspendingFunction ? (CoroutinesInvocationCallback) invocation : null);
ReactiveTransactionSupport txSupport = this.transactionSupportCache.computeIfAbsent(method, key -> {
Class<?> reactiveType =
(isSuspendingFunction ? (hasSuspendingFlowReturnType ? Flux.class : Mono.class) : method.getReturnType());
ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(reactiveType);
if (adapter == null) {
throw new IllegalStateException("Cannot apply reactive transaction to non-reactive return type: " +
method.getReturnType());
}
return new ReactiveTransactionSupport(adapter);
});
InvocationCallback callback = invocation;
if (corInv != null) {
callback = () -> CoroutinesUtils.invokeSuspendingFunction(method, corInv.getTarget(), corInv.getArguments());
}
/**
* 调用事务
*/
Object result = txSupport.invokeWithinTransaction(method, targetClass, callback, txAttr, (ReactiveTransactionManager) tm);
if (corInv != null) {
Publisher<?> pr = (Publisher<?>) result;
return (hasSuspendingFlowReturnType ? KotlinDelegate.asFlow(pr) :
KotlinDelegate.awaitSingleOrNull(pr, corInv.getContinuation()));
}
return result;
}
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);
}
if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
// Set rollback-only in case of Vavr failure matching our rollback rules...
TransactionStatus status = txInfo.getTransactionStatus();
if (status != null && txAttr != null) {
retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
}
/**
* 事务的提交,最里面其实也就是一个con.commit()
*/
commitTransactionAfterReturning(txInfo);
return retVal;
}
/**
* 回滚类型的事务走这里,带指定回滚类型的事务
*/
else {
Object result;
final ThrowableHolder throwableHolder = new ThrowableHolder();
try {
result = ((CallbackPreferringPlatformTransactionManager) ptm).execute(txAttr, status -> {
TransactionInfo txInfo = prepareTransactionInfo(ptm, txAttr, joinpointIdentification, status);
try {
Object retVal = invocation.proceedWithInvocation();
if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
return retVal;
}
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 {
throwableHolder.throwable = ex;
return null;
}
}
finally {
cleanupTransactionInfo(txInfo);
}
});
}
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;
}
// Check result state: It might indicate a Throwable to rethrow.
if (throwableHolder.throwable != null) {
throw throwableHolder.throwable;
}
return result;
}
}
代码很长我尽量分析与spring事务关联紧密的代码就好了,关键代码createTransactionIfNecessary(),字面意思理解:如果必要创建一个事务?何为创建事务?可以剧透一下,简单的说其实就是关闭事务自动提交。点进去createTransactionIfNecessary()。
tm、txAttr不为null,来到getTransaction()点进去查看是如何获取事务的,
getTransaction中的代码可以精简成如下几步理解
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException {
// Use defaults if no transaction definition given.
TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
/**
* 获取一个事务对象
* 注意:第一次获取到的事务对象里面并没有连接,且 contextholder == null
*/
Object transaction = doGetTransaction();
boolean debugEnabled = logger.isDebugEnabled();
/**
* 嵌套事务的将会走此if分支
* 事务是否存在(当前的transaction事务对象是否是激活状态且存在ConnectionHolder那么此处为true)
*/
if (isExistingTransaction(transaction)) {
/**
* 事务是否存在(当前的transaction事务对象是否是激活状态且ConnectionHolder!=null那么此处为true)
*/
return handleExistingTransaction(def, transaction, debugEnabled);
}
if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
}
if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
/**
* 注意⚠️PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED传播行为都是走这一段代码
*/
else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
}
try {
/**
* getTransaction--开启一个新事务
* 成功:获取事务成功
* 失败:获取事务失败
*/
return startTransaction(def, transaction, debugEnabled, suspendedResources);
} catch (RuntimeException | Error ex) {
resume(null, suspendedResources);
throw ex;
}
}
else {
// Create "empty" transaction: no actual transaction, but potentially synchronization.
if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
logger.warn("Custom isolation level specified but no actual transaction initiated; " +
"isolation level will effectively be ignored: " + def);
}
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
}
}
哎呀又是一大坨代码,不过这里面的代码都挺重要的,着重分析!
@Override
protected Object doGetTransaction() {
/**
* 新建一个事务对象
*/
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
/**
* 设置事务是否允许嵌套
*/
txObject.setSavepointAllowed(isNestedTransactionAllowed());
/**
* 从threadlocal中获取连接对象(ConnectionHolder)
* 第一次获取到的ConnectionHolder为null
* obtainDataSource():DataSourceTransactionManager中配置过的数据源
*/
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
/**
* 事务对象中设置连接ConnectionHolder,ConnectionHolder中包含连接conection
*/
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
点进来其实就是doGetResource(),从ThrealLocal(dataSource,contextHolder)中获取connectionHolder对象,第一个事务获取到的contextHolder为null
private static Object doGetResource(Object actualKey) {
/**
* actualKey:DataSourceTransactionManager中配置过的数据源
* resources:ThreadLocal
Map<Object, Object> map = resources.get();
/**
* 第一次肯定为null
*/
if (map == null) {
return null;
}
/**
* 这个map的
* key:dataSource
* value:contextHolder
*/
Object value = map.get(actualKey);
if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) {
map.remove(actualKey);
if (map.isEmpty()) {
resources.remove();
}
value = null;
}
/**
* 返回一个connectionHolder
*/
return value;
}
外层事务会走这里
private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {
/**
* getTransactionSynchronization:return this.transactionSynchronization(一个允许事务是否同步的标识符号)
* SYNCHRONIZATION_NEVER:事务永远不会同步
* 这俩个货不相等,那么开启一个新事务
*/
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
/**
* ⚠️:newTransaction属性为new
* DefaultTransactionStatus:事务状态对象,
* suspendedResources:上一个事务的ConnectionHolder
*/
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
/**
* startTransaction()->doBegin()
* 开启事务:其实也就是打开一个连接改变autoCommit的状态而已
*/
doBegin(transaction, definition);
/**
*
*/
prepareSynchronization(status, definition);
return status;
}
doBegin代码很长,精简流程描述如下
protected void doBegin(Object transaction, TransactionDefinition definition) {
/**
* 事务对象转型
*/
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
/**
* hasConnectionHolder: return(this.connectionHolder != null);
* isSynchronizedWithTransaction:return this.synchronizedWithTransaction;
*/
if (!txObject.hasConnectionHolder() ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
/**
* 从数据源中获取连接
*/
Connection newCon = obtainDataSource().getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
/**
* 给此时的事务对象设置一个ConnectionHolder进去,标记是一个新连接
*/
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
/**
* 走到这的事务一般事务传播行为都是Propagation.REQUIRES_NEW
* 设置当前的ConnectionHolder允许事务同步,也就是允许嵌套事务都是一个新的事务
*/
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
/**
* 获取当前事务的连接对象
*/
con = txObject.getConnectionHolder().getConnection();
/**
* 获取@Transaction注解中的事务隔离级别
*/
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
/**
* 给事务对象设置传播行为
*/
txObject.setPreviousIsolationLevel(previousIsolationLevel);
/**
* 给事务对象设置只读
*/
txObject.setReadOnly(definition.isReadOnly());
if (con.getAutoCommit()) {
/**
* 还原:自动提交为true
*/
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
/**
* 关闭事务自动提交
*/
con.setAutoCommit(false);
}
/**
* 与只读事务有关
*/
prepareTransactionalConnection(con, definition);
/**
* 给当前事务标记一个状态:活跃事务
*/
txObject.getConnectionHolder().setTransactionActive(true);
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
if (txObject.isNewConnectionHolder()) {
/**
* 将ConnectionHolder与数据源进行一一绑定
* key:DataSource
* value:ConnectionHolder
*/
TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
}
} catch (Throwable ex) {
if (txObject.isNewConnectionHolder()) {
/**
* 释放连接
*/
DataSourceUtils.releaseConnection(con, obtainDataSource());
txObject.setConnectionHolder(null, false);
}
throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
}
}
嵌套事务会走下面的代码,读者现在大致浏览一下下面的代码即可,下文有细说
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);
}
/**
* 重点:PROPAGATION_REQUIRES_NEW
*/
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
if (debugEnabled) {
logger.debug("Suspending current transaction, creating new transaction with name [" +
definition.getName() + "]");
}
/**
* 清空当前事务对象中的contextholder = null,执行这行代码说明,嵌套事务与原先事务使用的不是同一个连接对象
*/
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() + "]");
}
/**
* 默认为true
*/
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
*/
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);
}
}
/**
* 默认的事务传播行为:PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.用的是同一个连接,且嵌套的事务为旧的事务
*/
// 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);
}
PROPAGATION_NEVER:直接抛出异常,存在嵌套事务立马抛出异常。鸡肋
PROPAGATION_NOT_SUPPORTED:挂起外层事务,标记此事务不是最新的事务,不是最新的事务不会进行提交操作。个人感觉好鸡肋这个,你不加事务注解不也一样吗。
PROPAGATION_REQUIRES_NEW:此种状态嵌套事务先是将事务对象中的connectionHolder设置为null,为的是在startTransaction()的时候,为当前事务开辟一个新的连接。(也就是上图定义的每次开启新的事务)
PROPAGATION_NESTED:设置回滚点,标记当前事务为非最新的事务,如果某个子事务回滚,外层事务并没有吞掉子事务的异常,那么会引起外层事务回滚,由于所有事务都是用的一个连接,那么外层事务回滚的效果就是造成所有事务的全部回滚
PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED :默认传播行为,标记事务状态为非新的。
PROPAGATION_REQUIRED与PROPAGATION_SUPPORTS的区别在于:
只是标记事务状态不是新的,相当于还是在最外层的事务中进行执行。加入外层事务是这个意思
最外层事务直接会开启一个新的事务
在进行火炬传递的期间出现异常,那么会进行回滚操作。我们直接来看看spring是怎么回滚的,点进去rollback()
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 {
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;
}
}
}
}
对事务状态进行了一个转型操作,接着processRollback(),点进去processRollback()接着看
@Override
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);
}
仔细观察spring的回滚源码,大体简化步骤分为如下几步
private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
try {
boolean unexpectedRollback = unexpected;
try {
triggerBeforeCompletion(status);
/**
* 如果有回滚点,按照回滚点回滚
*/
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Rolling back transaction to savepoint");
}
status.rollbackToHeldSavepoint();
}
/**
* 如果是一个新的事务(存在事务且事务是最新的),回滚对应的这个新的事务中的DML语句
*/
else if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction rollback");
}
doRollback(status);
}
else {
// Participating in larger transaction
if (status.hasTransaction()) {
/**
* isLocalRollbackOnly:return rollbackOnly回滚部分
* isGlobalRollbackOnParticipationFailure:参与失败造成的全部回滚 return this.globalRollbackOnParticipationFailure;
*/
if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
if (status.isDebug()) {
logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
}
/**
* 设置rollbackOnly属性为true,在最外层事务提交的时候会触发回滚操作
*/
doSetRollbackOnly(status);
} else {
if (status.isDebug()) {
logger.debug("Participating transaction failed - letting transaction originator decide on rollback");
}
}
}
else {
logger.debug("Should roll back transaction but cannot - no transaction available");
}
// 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;
}
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
// Raise UnexpectedRollbackException if we had a global rollback-only marker
if (unexpectedRollback) {
throw new UnexpectedRollbackException(
"Transaction rolled back because it has been marked as rollback-only");
}
} finally {
cleanupAfterCompletion(status);
}
}
从事务状态中获取到连接进行回滚操作
@Override
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);
}
}
进行事务的提交操作,在这里面完成,点进去commit()
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());
}
}
⚠️在事务提交之前还有一次判断是否需要回滚的操作!,一般来说如果ResourceHolderSupport中的RollbackOnly属性被修改为true那么会进行回滚操作,反之接着才是提交操作
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;
/**
* AbstractTransactionStatus.RollbackOnly是否为true,默认是false
*/
if (defStatus.isLocalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Transactional code has requested rollback");
}
//回滚操作
processRollback(defStatus, false);
return;
}
/**
* shouldCommitOnGlobalRollbackOnly()默认返回false
* isGlobalRollbackOnly():ResourceHolderSupport中的RollbackOnly属性为true那么也会进行回滚操作
*/
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);
}
我这里就不贴代码了,有回滚点抹掉回滚点不进行事务提交操作、只有是新事务才会来进行提交的,到此spring事务的整个执行流程算是完结撒花了,别着急走,来看下下文的配套图文解说吧
注意回滚操作是根据连接回滚的,commit的之前还有一次判断是否需要回滚。这俩点对于事务回滚的理解十分重要!。
@Transactional(propagation = Propagation.NEW)
public void a() {
this.update(new UpdateWrapper<User>().eq("id", 52).set("age", 100));
System.out.println("a事务更新完毕");
userService.b();
userService.c();
userService.d();
}
上述代码的运行流程用伪代码表示如下,嵌套事务简化版伪代码如下
有了这个伪代码,我们再来分析一下真实事务失效的场景吧!
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void a() {
this.update(new UpdateWrapper<User>().eq("id", 52).set("age", 100));
System.out.println("a事务更新完毕");
userService.b();
userService.c();
userService.d();
//REQUIRES_NEW事务传播行为 : a失败,b、c、d成功
//Propagation.NESTED事务传播行为 :a、b、c、d失败
//throw new NullPointerException();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void b() {
this.update(new UpdateWrapper<User>().eq("id", 53).set("age", 100));
System.out.println("b事务更新完毕");
//REQUIRES_NEW事务传播行为 : a、b、c、d失败
//Propagation.NESTED事务传播行为 :a成功,b、c、d失败
//throw new NullPointerException();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void c() {
this.update(new UpdateWrapper<User>().eq("id", 54).set("age", 100));
System.out.println("c事务更新完毕");
//REQUIRES_NEW事务传播行为 : b成功,a、c、d失败
//Propagation.NESTED事务传播行为 :a、b成功,c、d失败
//throw new NullPointerException();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void d() {
this.update(new UpdateWrapper<User>().eq("id", 55).set("age", 100));
System.out.println("d事务更新完毕");
//REQUIRES_NEW事务传播行为 : b、c成功,a、d失败
//Propagation.NESTED事务传播行为 :a、b、c成功,d失败
//throw new NullPointerException();
}
事务a、b、c、d执行回滚情况如下。
执行结果 | a事务 | b事务 | c事务 | d事务 | |
---|---|---|---|---|---|
抛出异常 | |||||
a事务 | x | y | y | y | |
b事务 | x | x | x | x | |
c事务 | x | y | x | x | |
d事务 | x | y | y | x |
b事务抛出异常,为什么a、b、c、d事务都会进行回滚呢?
b事务抛出的异常具有传递性连着会被a事务捕获,因此a、b会回滚。因为b事务抛出异常后直接代码都不会在接着向下执行了,因此c、d事务压根执行不到,因此a、b、c、d事务都更新失败。同理验证上述表格的所有情况
事务a、b、c、d执行回滚情况如下。Propagation.NESTED虽说也是同一个线程中的事务共享同一个连接,但是会创建保存点,回滚也是根据回滚点进行回滚的
此表格针对上图这种情况分析的
执行结果 | a事务 | b事务 | c事务 | d事务 | |
---|---|---|---|---|---|
抛出异常 | |||||
a事务 | x | x | x | x | |
b事务 | y | x | x | x | |
c事务 | y | y | x | x | |
d事务 | y | y | y | x |
为什么b事务抛出异常a事务不会回滚呢?为什么c、d事务回滚了?
同理分析只有c事务抛出异常的情况下,为什么a、b更新成功,c、d更新失败呢?
invokeWithinTransaction {
//获取@Transaction注解上的源属性
TransactionAttributeSource tas = getTransactionAttributeSource();
//tas理论上和txAttr差不多
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
//获取事务管理器
final TransactionManager tm = determineTransactionManager(txAttr);
if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
TransactionInfo txInfo = createTransactionIfNecessary {
status = tm.getTransaction(txAttr);
{
// 获取一个事务对象,第一次获取到的事务对象里面并没有连接,且且ConnectionHolder = null
Object transaction = doGetTransaction();
{
//新建一个事务对象
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
//设置事务是否允许嵌套
txObject.setSavepointAllowed(isNestedTransactionAllowed());
//从threadlocal中获取连接对象(ConnectionHolder)、第一次获取到的ConnectionHolder为null
ConnectionHolder conHolder = {
/**
* actualKey:连接池中获取的数据源
* resources:ThreadLocal
Map < Object, Object > map = resources.get();
/**
* 第一次肯定为null
*/
if (map == null) {
return null;
}
/**
* ⚠️:这里只是放进去我们配置事务管理器中的数据源
* key:dataSource
* value:contextHolder
*/
return map.get(obtainDataSource());
}
/**
* 事务对象中设置连接ConnectionHolder,ConnectionHolder对象包含conection属性
* ⚠️newConnectionHolde:false
*/
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
//事务是否存在(当前的transaction事务对象是否是激活状态且存在ConnectionHolder那么此处为true)
if (isExistingTransaction(transaction)) {
//⚠️嵌套事务走这里,且直接return
return handleExistingTransaction(def, transaction, debugEnabled);
}
if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
//true:开启事务成功,false:开启事务失败
//此方法,默认嵌套事务都会开启一个新事务
return startTransaction(def, transaction, debugEnabled, suspendedResources);
{
//开启事务,设置autoCommit = false。标记事务状态
doBegin(transaction, definition);
{
/**
* hasConnectionHolder: return(this.connectionHolder != null);
* isSynchronizedWithTransaction:return this.synchronizedWithTransaction;
*/
//判断条件等同:connectionHolder == null || synchronizedWithTransaction
//确保PROPAGATION_REQUIRES_NEW类型的事务嵌套依然会开辟新的连接
if (!txObject.hasConnectionHolder() ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
//⚠️:newConnectionHolde:true
//⚠️:这里为ConnectionHolde开辟了一个新的连接
txObject.setConnectionHolder(new ConnectionHolder(obtainDataSource().getConnection()), true);
}
txObject.getConnectionHolder().setTransactionActive(true);
con = txObject.getConnectionHolder().getConnection();
con.setAutoCommit(false);
}
prepareSynchronization(status, definition);
}
}
}
}
try {
//火炬传递
retVal = invocation.proceedWithInvocation();
} catch (Throwable ex) {
//事务回滚
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
//事务的提交
commitTransactionAfterReturning(txInfo);
}
}