Spring事务
注解一:@EnableTransactionManagement
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
/** 是否使用cglib代理 默认是jdk代理 这个参数 也会影响 EnableAspectJAutoProxy注解生成代理对象的方式
*/
boolean proxyTargetClass() default false;
/**
* 表明会使用哪种代理方式 aspectj 或者spring AOP
*/
AdviceMode mode() default AdviceMode.PROXY;
/** 通知的优先级
*/
int order() default Ordered.LOWEST_PRECEDENCE;
}
这个注解 导入了TransactionManagementConfigurationSelector类
TransactionManagementConfigurationSelector
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
/**
* 导入了两个配置类AutoProxyRegistrar ProxyTransactionManagementConfiguration
*/
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[] {AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {determineTransactionAspectClass()};
default:
return null;
}
}
private String determineTransactionAspectClass() {
return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
}
}
看selectImports
方法,默认是adviceMode 是 PROXY,导入了AutoProxyRegistrar
和ProxyTransactionManagementConfiguration
,第一个类用于开启代理,
这个类是 主要用于 将 @EnableTransactionManagement
注解上的信息进行解析后,再往容器中注册一个BeanDefinition,这个BeanDefinition被用于代理类的创建,BeanDefinition内的类型是InfrastructureAdvisorAutoProxyCreator
,InfrastructureAdvisorAutoProxyCreator
实现了BeanPostProcess
,
注: @EnableTransactionManagement
跟@EnableAspectJAutoProxy
都是调用这个方法 ,由于传入参数的类型不同,但是注入的BeanDefinition中的名称会一样的,获取会导致类的覆盖,@EnableTransactionManagement
传入的是InfrastructureAdvisorAutoProxyCreator
,而@EnableAspectJAutoProxy
传入的是AnnotationAwareAspectJAutoProxyCreator
,两个类的优先级比较的话,AnnotationAwareAspectJAutoProxyCreator
更高,具体代码在AopConfigUtils#registerOrEscalateApcAsRequired.
ProxyTransactionManagementConfiguration
这是一个配置类,用于注册事务管理器组件,一共注册三个组件,
- BeanFactoryTransactionAttributeSourceAdvisor: 事务增强器,其中有两个属性,一个是标签解析器(PointCut),还有一个拦截器
- TransactionAttributeSource: 用于解析@Transacational注解
- TransactionInterceptor: 方法拦截器,这个类继承了MethodInterceptor,那么其中的核心方法就是invoke方法,
TransactionInterceptor#invoke
@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction... 核心方法
return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}
invoke内部调用的invokeWithinTransaction
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
//得到 TransactionAttributeSource 这个是之前注册进去的,
//1.获得事务属性
TransactionAttributeSource tas = getTransactionAttributeSource();
//解析注解 获得属性
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
// 获得对应的事务管理器
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
//切点名称 (类名+方法名)会直接作为事务名称
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
//2.创建事务
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal;
try {
//3。执行业务逻辑
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception 4。出现异常 在异常情况下完成事务
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
//5。清除事务信息
cleanupTransactionInfo(txInfo);
}
//6。提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
final ThrowableHolder throwableHolder = new ThrowableHolder();
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
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;
}
}
}
代码分成了两块
- 标准式事务管理
- 回调来完成事务管理
标准的事务管理分为6个步骤
- 获取事务属性
- 创建事务
- 执行业务逻辑
- 异常情况下完成事务
- 清除事务信息
- 提交事务
获取事务属性
通过getTransactionAttribute 方法来解析注解,获取属性,会优先从缓存中找,找不到的进行构建
@Override
@Nullable
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
if (method.getDeclaringClass() == Object.class) {
return null;
}
//从缓存中找
Object cacheKey = getCacheKey(method, targetClass);
TransactionAttribute cached = this.attributeCache.get(cacheKey);
if (cached != null) {
if (cached == NULL_TRANSACTION_ATTRIBUTE) {
return null;
}
else {
return cached;
}
}
else {
// We need to work it out.缓存中没有去执行 得到后放入到缓存中
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
// Put it in the cache.
//如果结果为null 也放入到缓存中 进行一个标志 表示不需要事务进行管理
if (txAttr == null) {
this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
}
else {
String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
if (txAttr instanceof DefaultTransactionAttribute) {
((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
}
if (logger.isTraceEnabled()) {
logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
}
this.attributeCache.put(cacheKey, txAttr);
}
return txAttr;
}
}
@Nullable
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
// Don't allow no-public methods as required. 放在非public上不生效
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
// The method may be on an interface, but we need attributes from the target class.
// If the target class is null, the method will be unchanged.
//method 可能是接口的方法,specificMethod是实际的方法
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
// First try is the method in the target class.
//先从目标方法上中找
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAttr != null) {
return txAttr;
}
// Second try is the transaction attribute on the target class.
//在当前类上去找
txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
//降级到接口 与接口方法中找
if (specificMethod != method) {
// Fallback is to look at the original method.
txAttr = findTransactionAttribute(method);
if (txAttr != null) {
return txAttr;
}
// Last fallback is the class of the original method.
txAttr = findTransactionAttribute(method.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
}
return null;
}
注意:
computeTransactionAttribute
方法中 第一个if判断,对于方法的作用范围有一个判断,非public修饰的方法不会生效
computeTransactionAttribute获取注解信息,是一个逐渐降级的过程,从一开始的在对应方法上找,再到当前类上找,最后再到方法实现的接口上找
在解析完成后,当解析的结果是一个null 也会被放入缓存中,
创建事务
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
// If no name specified, apply method identification as transaction name.
//不特殊的话 就用方法名作为事务名称
if (txAttr != null && txAttr.getName() == null) {
txAttr = new DelegatingTransactionAttribute(txAttr) {
@Override
public String getName() {
return joinpointIdentification;
}
};
}
TransactionStatus status = null;
if (txAttr != null) {
if (tm != null) {
//调用事务管理器的方法 获取一个事务并返回状态
status = tm.getTransaction(txAttr);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
"] because no transaction manager has been configured");
}
}
}
//封装到 TransactionInfo对象中 并将TransactionInfo绑定到当前线程
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
创建事务 就是创建了一个TransactionInfo
,其中包含了事务管理器,事务属性,事务状态,上一个事务的信息(只在嵌套事务中被用到)
核心方法就是
- getTransaction
- prepareTransactionInfo
这是spring事务中最麻烦的,涉及到了事务的传播行为
事务的传播行为
@Override
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
//得到一个数据库事务对象封装了一个从当前线程中获取到的连接 一开始 是返回一个没有数据库连接的DataSourceTransactionObject
Object transaction = doGetTransaction();
// Cache debug flag to avoid repeated checks.
boolean debugEnabled = logger.isDebugEnabled();
if (definition == null) {
// Use defaults if no transaction definition given.
definition = new DefaultTransactionDefinition();
}
//是否存在事务 只有 required_new 的情况 会开启一个线程 有些是直接加入了外部的事务 比如 supports、required、mandatory
// 而nested 不仅计入了外部事务 还设置了一个保存点 如果事务发生了异常 只有回滚到保存点 由于直接复用外部事务 嵌套事务 随着外部事务的回滚而回滚
if (isExistingTransaction(transaction)) {
//检查传播类型进行不同处理 这里进去是对嵌套事务的梳理
// Existing transaction found -> check propagation behavior to find out how to behave.
return handleExistingTransaction(definition, transaction, debugEnabled);
}
// Check definition settings for new transaction.
//超时检验 默认-1 不进行校验
if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
}
// No existing transaction found -> check propagation behavior to find out how to proceed.
// mandatory 没有事务存在 抛出异常
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
//创建新事务
//如果存在同步 就把注册的同步挂起 传入null的话 就返回null
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
}
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
//根据之前事务定义的信息 构造一个事务状态对象
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
//开启一个新事务 并将数据库连接 绑定要线程上
doBegin(transaction, definition);
//激活同步
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException | Error 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);
}
//创建一个空事务 没有回滚设置 与事务提交
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
//绑定要当前线程上
return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
}
}
这段代码 被分成了两种情况来考虑
一种是直接调用事务
还是一种是事务内的嵌套事务
在代码中 可以发现在嵌套事务的情况下,只有传播级别为required_new
的情况才会去调用startTransaction
方法,也就是开启一个新事务,其他情况都是复用外围的事务,
我们看一段代码 位于 AbstractTransactionStatus# handleExistingTransaction,是嵌套事务中对于 NOT_SUPPORTED类型的事务的处理,基本上对于代码已经注释了,
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
if (debugEnabled) {
logger.debug("Suspending current transaction");
}
//挂起 挂起是指 清空外部事务绑定在线程的同步
// 挂起后 将来还要恢复的 要将清除的信息 保存到当前的事务上,当当前事务完成后,保证外围事务也能运行
// suspendedResources 标示挂起的资源
Object suspendedResources = suspend(transaction);
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
//创建一个新事务 标示不存在一个真正的事务 不需要进行回滚
return prepareTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
这里完成了一个是对于外部事务的挂起,挂起分成两个动作
- 清空外部事务在线程上的同步
- 挂起后为了后续线程的恢复,要将信息保存下来,方便后续将事务进行恢复
这里调用的是 prepareTransactionStatus方法,而不是
startTransaction两者的区别就是 后者会从数据库中获取链接,而前者不会获取链接,在PROPAGATION_REQUIRES_NEW 传播类型下 就是直接使用
startTransaction`。
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 {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
//这里将 旧事务的信息 也加进去了 有自己的提交跟回滚机制
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException | Error beginEx) {
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
}