一、簡介
接著上篇 資料庫事務簡介,來聊聊 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:是 Spring AOP 的頂層抽象,充當 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 物件中,便于內部事務運行結束后,恢復外層事務;
參考文章:
- Spring 事務實作分析
- Spring 中的 Advisor,Advice,Pointcut
- Spring事務失效的 8 大原因,這次可以吊打面試官了!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/270603.html
標籤:Java
上一篇:JDBC實作對資料庫的增刪改查
下一篇:12-選擇排序:簡單選擇排序
