一、簡介
接着上篇 數據庫事務簡介,來聊聊 Spring 事務。
Spring 本身並不實現事務,Spring 事務的本質還是底層數據庫對事務的支持,沒有數據庫事務的支持,Spring 事務就不會生效。
Spring 事務提供了一套抽象的事務管理,並且結合 Spring IOC 和 Spring AOP,簡化了應用程序使用數據庫事務,並且通過聲明式事務,可以做到應用程序無侵入的事務功能。例如使用 JDBC 操作數據庫,想要使用事務的步驟爲:
- 獲取連接 Connection conn= DriverManager.getConnection()
- 開啓事務 conn.setAutoCommit(true/false);
- 執行 CRUD
- 提交事務/回滾事務 conn.commit() / conn.rollback();
- 關閉連接 conn.close();
而採用了 Spring 事務後,只需要關注第三步的實現即可,其他的步驟都是 Spring 完成。
Spring 事務的本質其實就是 AOP 和 數據庫事務,Spring 將數據庫的事務操作提取爲切面,通過 AOP 的方式增強事務方法。
二、Spring 事務傳播行爲
PROPAGATION_REQUIRED:默認,如果當前沒有事務,就新建一個事務;如果當前存在事務,加入到這個事務中。
PROPAGATION_SUPPORTS:如果當前沒有事務,那麼就以非事務的形式執行;如果當前存在事務,加入到這個事務中。
PROPAGATION_MANDATORY:必須在一個事務中執行。如果當前沒有事務,則拋出異常;如果當前存在事務,加入到這個事務中。
PROPAGATION_REQUIRES_NEW:如果當前沒有事務,就新建一個事務;如果當前存在事務,就把當前事務掛起,新建一個事務。
PROPAGATION_NOT_SUPPORTED:當前不支持事務。如果當前沒有事務,那麼就以非事務的形式執行;如果當前存在事務,就把當前事務掛起,以非事務的形式執行。
PROPAGATION_NEVER:不能在事務中執行。如果當前沒有事務,那麼就以非事務的形式執行;如果當前存在事務,則拋出異常。
PROPAGATION_NESTED:如果當前沒有事務,就新建一個事務;如果當前存在事務,則在嵌套事務內執行。
三、使用 Spring 事務
1. 通過 PlatformTransactionManager使用(不推薦)
@org.junit.Test
public void test1() {
// 默認的事務定義
DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
PlatformTransactionManager transactionManager = SpringUtils.getBean(PlatformTransactionManager.class);
// 開啓事務
TransactionStatus transactionStatus = transactionManager.getTransaction(transactionDefinition);
try {
// do something
} catch (Exception e) {
// 事務回滾
transactionManager.rollback(transactionStatus);
}
// 事務提交
transactionManager.commit(transactionStatus);
}
2. 通過 TransactionTemplate 使用事務
@org.junit.Test
public void test2() {
PlatformTransactionManager transactionManager = SpringUtils.getBean(PlatformTransactionManager.class);
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
Boolean execute = transactionTemplate.execute(transactionStatus -> {
// do something
return Boolean.TRUE;
});
}
3. 聲明式事務
我們經常使用的基於 XML 配置或者註解的方式使用的事務方式。
@Transactional(rollbackFor = Exception.class)
public OrderDealResultDTO createOrder(OrderCreateParam orderCreateParam) { xxx }
四、實現原理
1. Spring 中的 Advisor,Advice,Point 概述
Advice:用於定義攔截行爲,祖先接口爲 org.aopalliance.aop.Advice
,該接口只是標識接口,應用中可直接實現 BeforeAdvice、ThrowsAdvice、MethodInterceptor、AfterReturningAdvice、IntroductionInterceptor 等子接口。
Pointcut:用於定義攔截目標集合,祖先接口爲 org.springframework.aop.Pointcut
。
Advisor:充當 Advice 和 Pointcut 的適配器,一般有 advice 和 pointcut 屬性。祖先接口爲 org.springframework.aop.Advisor
,應用中可直接使用 org.springframework.aop.support.DefaultPointcutAdvisor
。
2. BeanFactoryTransactionAttributeSourceAdvisor
Spring 事務把整個事務流程模板化,採用 AOP 的形式增強到需要事務的方法,BeanFactoryTransactionAttributeSourceAdvisor
就是 Spring 事務的增強方法,其中 Ponintcut 是 TransactionAttributeSourcePointcut
,Advice 是 TransactionInterceptor
。
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource());
advisor.setAdvice(transactionInterceptor());
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
}
return advisor;
}
因此,調用 Spring 事務方法,就委託給了 TransactionInterceptor 的 invoke 方法。
@Override
@Nullable
public Object invoke(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 TransactionAspectSupport's invokeWithinTransaction...
// Spring 事務處理邏輯
return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}
3. PlatformTransactionManager
PlatformTransactionManager 是 Spring 事務結構中的核心接口,Spring 並不直接管理事務,而是提供了多種事務管理器(JDBC、Hibernate、JTA 等),然後將事務管理的職責委託給這些事務管理器。
- TransactionDefinition:事務定義對象,封裝了 @Transactional 註解中設置的各種信息;
- TransactionStatus:表示一個事務狀態,在應用程序中可以通過 TransactionInterceptor.currentTransactionStatus() 的靜態函數獲取到;
- TransactionInfo:事務信息對象,包括一個事務所有的信息,包括事務管理器、事務定義對象、事務狀態對象、目標方法唯一標識等等;
4. org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// 1. 準備事務的基本信息
// If the transaction attribute is null, the method is non-transactional.
TransactionAttributeSource tas = getTransactionAttributeSource();
// 事務定義 TransactionAttribute 是 TransationDefinition 的子類
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)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
// 2. 開啓事務
// 如果必要纔會開啓事務,這裏會根據事務的傳播能力信息來決定是否開啓事務還是加入到一個已經存在的事務,這裏會涉及到事務的掛起
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
// 執行目標方法或者執行 AOP 攔截鏈中的下一個攔截器
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
// 3. 事務的回滾
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
// 清理事務信息
cleanupTransactionInfo(txInfo);
}
// 4. 提交事務
commitTransactionAfterReturning(txInfo);
return retVal;
}
// 省略下文
}
5. 其它
- TransationSynchronization:事務同步回調接口,在事務的各個點執行回調方法,比如掛起、繼續、提交前後,完成前後等。在 Spring-Mybatis 整合時,Mybatis 正是利用了 TransationSynchronization 同步器,才讓 Mybatis 的事務管理交給了 Spring 事務來管理。
- TransactionSynchronizationManager:事務同步回調接口的管理器,用來管理當前線程的事務,常用在事務執行點實現自己的一些邏輯,因此 TransactionSynchronizationManager 保存着事務運行過程中的一些狀態,比如數據庫連接等;
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void beforeCommit(boolean readOnly) {
// do something
}
@Override
public void afterCommit() {
// do something
}
});
- SuspendedResourcesHolder:用來記錄掛起事務的運行時信息,這些信息就是 TransactionSynchronizationManager 中記錄的事務信息。然後將這些信息保存在新的 DefaultTransactionStatus 對象中,便於內部事務運行結束後,恢復外層事務;
參考文章: