深入解析Spring事務(wù)原理,一文帶你全面理解
前言
在Spring中,事務(wù)管理主要通過AOP功能實(shí)現(xiàn),對(duì)方法前后進(jìn)行攔截,將事務(wù)處理的功能編織到攔截的方法中,Spring支持編程式事務(wù)管理和聲明式事務(wù)管理兩種方式。
- 聲明式事務(wù)
- @Transactional
- 編程式事務(wù)
TransactionTemplate
TransactionManager
四大特性
- 原子性(Atomicity):一個(gè)事務(wù)中的所有操作,要么都完成,要么都不執(zhí)行。對(duì)于一個(gè)事務(wù)來說,不可能只執(zhí)行其中的一部分。
- 一致性(Consistency):數(shù)據(jù)庫總是從一個(gè)一致性的狀態(tài)轉(zhuǎn)換到另外一個(gè)一致性狀態(tài),事務(wù)前后數(shù)據(jù)的完整性必須保持一致。。
- 隔離性(Isolation):一個(gè)事務(wù)所做的修改在最終提交以前,對(duì)其它事務(wù)是不可見的,多個(gè)事務(wù)之間的操作相互不影響。
- 持久性(Durability):持久性是指一個(gè)事務(wù)一旦被提交,它對(duì)數(shù)據(jù)庫中數(shù)據(jù)的改變就是永久性的,接下來即使數(shù)據(jù)庫發(fā)生故障也不應(yīng)該對(duì)其有任何影響。
隔離級(jí)別
- Read Uncommitted(讀取未提交內(nèi)容):一個(gè)事務(wù)可以看到其他事務(wù)已執(zhí)行但是未提交的結(jié)果。本隔離級(jí)別很少用于實(shí)際應(yīng)用,因?yàn)樗男阅芤膊槐绕渌?jí)別好多少,并且存在臟讀問題。
- Read Committed(讀取已提交內(nèi)容):一個(gè)事務(wù)只能看到其他事務(wù)已執(zhí)行并已提交的結(jié)果(Oracle、SQL Server默認(rèn)隔離級(jí)別)。這種隔離級(jí)別支持不可重復(fù)讀,因?yàn)橥皇聞?wù)的其他實(shí)例在該實(shí)例處理期間可能會(huì)有新的commit,所以同一select可能返回不同結(jié)果。
- Repeatable Read(可重讀):同一事務(wù)的多個(gè)實(shí)例在并發(fā)讀取數(shù)據(jù)時(shí),會(huì)看到同樣的數(shù)據(jù)行(MySQL的默認(rèn)事務(wù)隔離級(jí)別)。InnoDB和Falcon存儲(chǔ)引擎通過多版本并發(fā)控制(MVCC)機(jī)制解決了不可重復(fù)讀問題,存在幻讀問題。
- Serializable(可串行化):最高的隔離級(jí)別,它通過強(qiáng)制事務(wù)排序,使之不可能相互沖突,從而解決幻讀問題。它是在每個(gè)讀的數(shù)據(jù)行上加上共享鎖。在這個(gè)級(jí)別,可能導(dǎo)致大量的超時(shí)現(xiàn)象和鎖競爭。
隔離級(jí)別 | 臟讀 | 不可重復(fù)讀 | 幻讀 |
Read Uncommitted | √ | √ | √ |
Read Committed | × | √ | √ |
Repeatable Read | × | × | √ |
Serializable | × | × | × |
傳播級(jí)別
傳播級(jí)別 | 含義 |
PROPAGATION_REQUIRED | 支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),則新建一個(gè)事務(wù) |
PROPAGATION_SUPPORTS | 支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),則以非事務(wù)進(jìn)行 |
PROPAGATION_MANDATORY | 支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),則拋異常 |
PROPAGATION_REQUIRES_NEW | 新建事務(wù),如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起 |
PROPAGATION_NESTED | 如果當(dāng)前存在事務(wù),則在嵌套事務(wù)內(nèi)執(zhí)行。如果沒有,則進(jìn)行與PROPAGATION_REQUIRED類似操作 |
PROPAGATION_NOT_SUPPORTED | 以非事務(wù)進(jìn)行,如果當(dāng)前存在事務(wù),則掛起事務(wù),執(zhí)行當(dāng)前邏輯,結(jié)束后恢復(fù)上下文的事務(wù) |
PROPAGATION_NEVER | 以非事務(wù)進(jìn)行,如果當(dāng)前存在事務(wù),則拋異常 |
案例
導(dǎo)入相關(guān)依賴
數(shù)據(jù)源、數(shù)據(jù)庫驅(qū)動(dòng)、spring-jdbc模塊
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.44</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
配置數(shù)據(jù)源
配置數(shù)據(jù)源、JdbcTemplate(Spring提供的簡化數(shù)據(jù)庫操作的工具)操作數(shù)據(jù)
@Bean
public DataSource dataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUsername("root");
dataSource.setPassword("root");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/scp");
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate(){
//Spring對(duì)@Configuration類會(huì)特殊處理;給容器中加組件的方法,多次調(diào)用都只是從容器中找組件
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
return jdbcTemplate;
}
數(shù)據(jù)訪問
@Repository
public class UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Transactional
public void insert(){
String sql = "INSERT INTO user (name,age) VALUES(?,?)";
String username = UUID.randomUUID().toString().substring(0, 5);
jdbcTemplate.update(sql, username,19);
int a = 1/0;
}
}
開啟事務(wù),配置事務(wù)管理器
@EnableTransactionManagement // 開啟事務(wù)
@ComponentScan("org.yian")
@Configuration
public class TxConfig {
//數(shù)據(jù)源
@Bean
public DataSource dataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUsername("root");
dataSource.setPassword("root");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/scp");
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate(){
//Spring對(duì)@Configuration類會(huì)特殊處理;給容器中加組件的方法,多次調(diào)用都只是從容器中找組件
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
return jdbcTemplate;
}
//注冊(cè)事務(wù)管理器在容器中
@Bean
public PlatformTransactionManager transactionManager(){
return new DataSourceTransactionManager(dataSource());
}
}
測試類
@Test
public void test01(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(TxConfig.class);
UserService userService = applicationContext.getBean(UserService.class);
userService.insertUser();
applicationContext.close();
}
原理
Spring 事務(wù)管理的實(shí)現(xiàn)原理主要涉及兩個(gè)方面:事務(wù)管理器和代理機(jī)制:
- 事務(wù)管理器(Transaction Manager):
Spring通過PlatformTransactionManager接口定義了事務(wù)管理器的標(biāo)準(zhǔn)。這個(gè)接口有多個(gè)實(shí)現(xiàn),包括常用的DataSourceTransactionManager、JpaTransactionManager、HibernateTransactionManager等,每個(gè)都專門用于不同的持久化技術(shù)。
事務(wù)管理器的主要職責(zé)是開始、提交或回滾事務(wù)。當(dāng)使用聲明式事務(wù)管理時(shí),開發(fā)者只需要配置相應(yīng)的事務(wù)管理器,而不必親自編寫事務(wù)管理的代碼
- 代理機(jī)制:
Spring 通過代理機(jī)制為事務(wù)管理提供支持。它使用AOP來在方法調(diào)用前后添加額外的邏輯,即切面。在事務(wù)管理中,這個(gè)額外的邏輯包括開啟、提交或回滾事務(wù)。
當(dāng)使用聲明式事務(wù)管理時(shí),Spring 會(huì)動(dòng)態(tài)創(chuàng)建一個(gè)代理對(duì)象,該代理對(duì)象包裝了目標(biāo)對(duì)象(擁有業(yè)務(wù)邏輯的對(duì)象)。在方法調(diào)用時(shí),代理對(duì)象會(huì)在執(zhí)行前后添加事務(wù)管理的邏輯
@EnableTransactionManagement:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({TransactionManagementConfigurationSelector.class})
public @interface EnableTransactionManagement {
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Integer.MAX_VALUE;
}
TransactionManagementConfigurationSelector:
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
public TransactionManagementConfigurationSelector() {
}
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[]{AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[]{this.determineTransactionAspectClass()};
default:
return null;
}
}
private String determineTransactionAspectClass() {
return ClassUtils.isPresent("javax.transaction.Transactional", this.getClass().getClassLoader()) ? "org.springframework.transaction.aspectj.AspectJJtaTransactionManagementConfiguration" : "org.springframework.transaction.aspectj.AspectJTransactionManagementConfiguration";
}
}
EnableTransactionManagement 會(huì)利用 TransactionManagementConfigurationSelector 給容器中會(huì)導(dǎo)入兩個(gè)組件 AutoProxyRegistrar、 ProxyTransactionManagementConfiguration
AutoProxyRegistrar:
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean candidateFound = false;
Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
Iterator var5 = annTypes.iterator();
while(var5.hasNext()) {
String annType = (String)var5.next();
AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
if (candidate != null) {
Object mode = candidate.get("mode");
Object proxyTargetClass = candidate.get("proxyTargetClass");
if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() && Boolean.class == proxyTargetClass.getClass()) {
candidateFound = true;
if (mode == AdviceMode.PROXY) {
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean)proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
}
AutoProxyRegistrar 給容器中注冊(cè)一個(gè) InfrastructureAdvisorAutoProxyCreator 組件,利用后置處理器機(jī)制在對(duì)象創(chuàng)建以后,包裝對(duì)象,返回一個(gè)代理對(duì)象(增強(qiáng)器),代理對(duì)象執(zhí)行方法利用攔截器鏈進(jìn)行調(diào)用
ProxyTransactionManagementConfiguration:
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource);
advisor.setAdvice(transactionInterceptor);
if (this.enableTx != null) {
advisor.setOrder((Integer)this.enableTx.getNumber("order"));
}
return advisor;
}
ProxyTransactionManagementConfiguration 給容器中注冊(cè)事務(wù)增強(qiáng)器
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
事務(wù)增強(qiáng)器要用事務(wù)注解的信息,AnnotationTransactionAttributeSource解析事務(wù)注解
public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource);
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
事務(wù)攔截器TransactionInterceptor保存了事務(wù)屬性信息,事務(wù)管理器,并且實(shí)現(xiàn)了 MethodInterceptor,在目標(biāo)方法執(zhí)行的時(shí)候執(zhí)行攔截器鏈(事務(wù)攔截器)
TransactionAspectSupport:
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, InvocationCallback invocation) throws Throwable {
TransactionAttributeSource tas = this.getTransactionAttributeSource();
TransactionAttribute txAttr = tas != null ? tas.getTransactionAttribute(method, targetClass) : null;
TransactionManager tm = this.determineTransactionManager(txAttr);
Object retVal;
if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
boolean isSuspendingFunction = KotlinDetector.isSuspendingFunction(method);
boolean hasSuspendingFlowReturnType = isSuspendingFunction && "kotlinx.coroutines.flow.Flow".equals((new MethodParameter(method, -1)).getParameterType().getName());
ReactiveTransactionSupport txSupport = (ReactiveTransactionSupport)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());
} else {
return new ReactiveTransactionSupport(adapter);
}
});
retVal = txSupport.invokeWithinTransaction(method, targetClass, invocation, txAttr, (ReactiveTransactionManager)tm);
return isSuspendingFunction ? (hasSuspendingFlowReturnType ? TransactionAspectSupport.KotlinDelegate.asFlow((Publisher)retVal) : TransactionAspectSupport.KotlinDelegate.awaitSingleOrNull((Publisher)retVal, ((CoroutinesInvocationCallback)invocation).getContinuation())) : retVal;
} else {
PlatformTransactionManager ptm = this.asPlatformTransactionManager(tm);
String joinpointIdentification = this.methodIdentification(method, targetClass, txAttr);
.............................
.............................
.............................
- 先獲取事務(wù)相關(guān)的屬性
- 再獲取PlatformTransactionManager,如果事先沒有添加指定任何transactionmanger,最終會(huì)從容器中按照類型獲取一個(gè)PlatformTransactionManager
- 執(zhí)行目標(biāo)方法,如果異常,獲取到事務(wù)管理器,利用事務(wù)管理回滾操作;如果正常,利用事務(wù)管理器,提交事務(wù)