问题背景
大多数业务场景中会大量使用到数据库事务,我们知道Spring提供了@Transactional注解来支持数据库的事务,那么这个注解会在那些情况下生效呢?下面通过源代码重点介绍下
首先看看 Transactional 的定义
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Transactional {
// 事务传播机制
Propagation propagation() default Propagation.REQUIRED;
// 事务的隔离级别
Isolation isolation() default Isolation.DEFAULT;
/**
* 以下为异常处理 rollback 机制
*
*/
Class<? extends Throwable>[] rollbackFor() default {};
String[] rollbackForClassName() default {};
Class<? extends Throwable>[] noRollbackFor() default {};
String[] noRollbackForClassName() default {};
@Transactional 是基于AOP技术的数据库事务实现,Propagation是定义了如何使用数据库事务,Spring中七种Propagation类的事务属性详解:
-
REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
-
SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
-
MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。
-
REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
-
NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
-
NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
-
NESTED:支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。
AnnotationTransactionAttributeSource
继承自AbstractFallbackTransactionAttributeSource和接口TransactionAttributeSource
@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 {
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
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.isDebugEnabled()) {
logger.debug("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
}
this.attributeCache.put(cacheKey, txAttr);
}
return txAttr;
}
}
@Nullable
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
// 修饰 必须是 public
return null;
}
Method specificMethod = AopUtils.*getMostSpecificMethod*(method, targetClass);
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAttr != null) {
return txAttr;
}
txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAttr != null && ClassUtils.*isUserLevelMethod*(method)) {
return txAttr;
}
if (specificMethod != method) {
txAttr = findTransactionAttribute(method);
if (txAttr != **null**) {
return txAttr;
}
txAttr = findTransactionAttribute(method.getDeclaringClass());
if (txAttr != **null** && ClassUtils.*isUserLevelMethod*(method)) {
return txAttr;
}
}
return** null;
}
TransactionAspectSupport.class
private static final ThreadLocal<TransactionInfo> transactionInfoHolder = new NamedThreadLocal<>("Current aspect-driven transaction");
// 事务管理
@Nullable
private PlatformTransactionManager transactionManager;
// 事务属性配置
@Nullable
private TransactionAttributeSource transactionAttributeSource;
@Nullable
private BeanFactory beanFactory;
// 缓存
private final ConcurrentMap<Object, PlatformTransactionManager> transactionManagerCache = new ConcurrentReferenceHashMap<>(4);
@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();
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)) {
// 新建 TransactionInfo 对象
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null
try {
// 执行切入
retVal = invocation.proceedWithInvocation();
}catch (Throwable ex) {
// 异常处理
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}finally {
// 清除缓存信息
cleanupTransactionInfo(txInfo);
}
//执行 Commit
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) {
// 自定义rallback异常处理
if (txAttr.rollbackOn(ex)) {
if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
}else{
throw new ThrowableHolderException(ex);
}
} else {
throwableHolder.throwable = ex;
return null;
}
}finally{
cleanupTransactionInfo(txInfo);
}});
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;
}
}
}
/**
* 获取对应transaction的Manager
*/
@Nullable
protected PlatformTransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) {
if (txAttr == null || this.beanFactory == null) {
return getTransactionManager();
}
//. 按照 qualifier 超找 manager
String qualifier = txAttr.getQualifier();
if (StringUtils.hasText(qualifier)) {
return determineQualifiedTransactionManager(this.beanFactory, qualifier);
}else if (StringUtils.hasText(this.transactionManagerBeanName)) {
return determineQualifiedTransactionManager(**this**.beanFactory, this.transactionManagerBeanName);
}else {
// 创建Manager 并缓存
PlatformTransactionManager defaultTransactionManager = getTransactionManager();
if (defaultTransactionManager == null) {
defaultTransactionManager = this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
if (defaultTransactionManager == null) {
defaultTransactionManager = this.beanFactory.getBean(PlatformTransactionManager.class);
this.transactionManagerCache.putIfAbsent(
DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
}
}
return defaultTransactionManager;
}
}
// 获取方法名称
private String methodIdentification(Method method, @Nullable Class<?> targetClass,@Nullable TransactionAttribute txAttr) {
String methodIdentification = methodIdentification(method, targetClass);
if (methodIdentification == null) {
if (txAttr instanceof DefaultTransactionAttribute) {
methodIdentification = ((DefaultTransactionAttribute) txAttr).getDescriptor();
}
if (methodIdentification == null) {
methodIdentification = ClassUtils.*getQualifiedMethodName*(method, targetClass);
}
}
return methodIdentification;
}
// TransactionAttribute 生成对应的 TransactionInfo 此处为线程级别的TransactionInfo
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");
}
}
}
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
// 生成TransactionInfo,并维护status
protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,@Nullable TransactionAttribute txAttr, String joinpointIdentification,@Nullable TransactionStatus status) {
TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
if (txAttr != null) {
if (logger.isTraceEnabled()) {
logger.trace("Getting transaction for [" + txInfo.getJoinpointIdentification() + "]");
}
txInfo.newTransactionStatus(status);
}else {
if (logger.isTraceEnabled())
logger.trace("Don't need to create transaction for [" + joinpointIdentification +"]: This method isn't transactional.");
}
txInfo.bindToThread();
return txInfo;
}
protected void cleanupTransactionInfo(@Nullable TransactionInfo txInfo) {
if (txInfo != null) {
txInfo.restoreThreadLocalStatus();
}
}
private void restoreThreadLocalStatus() {
transactionInfoHolder.set(this.oldTransactionInfo);
}
protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" +txInfo.getJoinpointIdentification() + "]");
}
//此处才是真正 执行 commit txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
}
AbstractPlatformTransactionManager.class
实际Jdbc DataSource 中实现了DataSourceTransactionManager
@Override
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()) {
// 处理Rollback
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;
}
// 实际执行commit
processCommit(defStatus);
}
// rollback 处理
private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
try {
boolean unexpectedRollback = unexpected;
try {
// 生命周期 rollback 开始前
triggerBeforeCompletion(status);
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Rolling back transaction to savepoint");
}
status.rollbackToHeldSavepoint();
}else if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction rollback");
}
// 实际的rollback 触发
doRollback(status);
}else {
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");
}
}
}else {
logger.debug("Should roll back transaction but cannot - no transaction available");
}
if (!isFailEarlyOnGlobalRollbackOnly()) {
unexpectedRollback = **false**;
}
}
}catch (RuntimeException | Error ex) {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
throw ex;
}
// 生命周期 rollback 出发之后
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);
}
}
// 清理资源,处理transaction中断
private void cleanupAfterCompletion(DefaultTransactionStatus status) {
status.setCompleted();
//tm 清理
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());
}
}
// commit 处理
private void processCommit(DefaultTransactionStatus status) **throws** TransactionException {
try {
boolean beforeCompletionInvoked = false;
try {
boolean unexpectedRollback = false;
// 由子类实现
prepareForCommit(status);
triggerBeforeCommit(status);
triggerBeforeCompletion(status);
beforeCompletionInvoked = true;
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Releasing transaction savepoint");
}
unexpectedRollback = status.isGlobalRollbackOnly();
status.releaseHeldSavepoint();
}else if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction commit");
}
unexpectedRollback = status.isGlobalRollbackOnly();
// 由子类实现
doCommit(status);
}else if (isFailEarlyOnGlobalRollbackOnly()) {
unexpectedRollback = status.isGlobalRollbackOnly();
}
if (unexpectedRollback) {
throw new UnexpectedRollbackException("Transaction silently rolled back because it has been marked as rollback-only");
}
}catch (UnexpectedRollbackException ex) {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
throw ex;
}catch (TransactionException ex) {
if (isRollbackOnCommitFailure()) {
doRollbackOnCommitException(status, ex);
}else {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
}
throw ex;
}catch (RuntimeException | Error ex) {
if (!beforeCompletionInvoked) {
triggerBeforeCompletion(status);
}
// rollback 处理,最终由子类实现 doRollback 方法
doRollbackOnCommitException(status, ex);
throw ex;
}
try {
triggerAfterCommit(status);
}finally {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
}
}finally {
cleanupAfterCompletion(status);
}
}
TransactionSynchronizationUtils.class 帮助util类
public static void triggerBeforeCommit(boolean readOnly)
public static void triggerBeforeCompletion();
public static void triggerAfterCommit();
public static void invokeAfterCommit(@Nullable List<TransactionSynchronization> synchronizations)
public static void triggerAfterCompletion(int completionStatus)
public static void invokeAfterCompletion(@Nullable List<TransactionSynchronization> synchronizations,int completionStatus)
DataSourceTransactionManager 数据库相关TM
protected void doBegin(Object transaction, TransactionDefinition definition)
protected Object doSuspend(Object transaction)
protected void doResume(@Nullable Object transaction, Object suspendedResources)
protected void doCommit(DefaultTransactionStatus status)
protected void doRollback(DefaultTransactionStatus status)
protected void doSetRollbackOnly(DefaultTransactionStatus status)
protected void doCleanupAfterCompletion(Object transaction)
@Transactional使用场景
- @Transactional 是基于Java AOP 机制,所有对于 final 修饰的方法 不起作用,因为方法无法通过cglib和aop等生成代理类
- @Transactional 修饰的方法 必须为 public,其他方法都无法生成事务;这里主要还是继承带来的可见性导致
- @Transactional 修饰的方法所在类必须是Spring管理的Bean对象;因为Transaction事务使用了Bean的生命周期
- @Transactional 不支持多线程,这是因为事务是绑定在DataSource的数据库连接上,不同线程中的数据库连接实例不同。ThreadLocal管理connect
@Transactional 事务回滚总结
- 目前只有这三种传播特性才会创建新事务:REQUIRED,REQUIRES_NEW,NESTED。其他的都不支持事务,会抛出异常
- 事务的回滚是基于异常的处理,所有事物的回滚处理中,需要抓取到异常,这样用户代码中不应该处理异常,一旦处理了异常,事务Manager无法感知
- 自定义rollback异常需要根据实际情况继承,否则rollback的时候无法抓取对应的异常,从而让回滚动作失效
- 特别需要关注的是当一个事务中存在多个方法,或者存在嵌套的情况,需要防止过度回滚,需要在嵌套层直接处理异常。不在通知到上层事物进行回滚操作;这个机制在叫做savepoint保存点。在嵌套使用的情况下需要注意回滚的粒度
最后 @Transactional 虽然使用特别方便轻量,但是到来的问题也不少,有时候特别不好定位问题。所以使用需要谨慎。