SpringBoot AOP如何配置全局事務(wù)
SpringBoot的出現(xiàn)使得項目中使用事務(wù)變得非常簡單,有兩種使用方式,適合小型項目的注解事務(wù)(聲明式事務(wù)管理),適合大型項目的全局事務(wù)。
1、注解事務(wù)(次要)
注解事務(wù)使用只用兩步,開啟事務(wù)注解功能,使用事務(wù)注解功能,并且每步都只有使用一個注解。
第一步
開啟事務(wù)注解功能@EnableTransactionManagement
在主啟動類中添加注解@EnableTransactionManagement
即可。
package com.gx; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.transaction.annotation.EnableTransactionManagement; @EnableTransactionManagement //開啟事務(wù)注解功能 @SpringBootApplication public class Ch09SpringbootTransAnnoApplication { public static void main(String[] args) { SpringApplication.run(Ch09SpringbootTransAnnoApplication.class, args); } }
第二步
使用事務(wù)注解功能@Transactional
在service接口實現(xiàn)類或接口實現(xiàn)類方法上添加@Transactional
即可。
package com.gx.service.impl; import com.gx.service.StudentService; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.gx.domain.Student; @Service public class StudentServiceImpl implements StudentService { @Transactional //使用注解事務(wù) @Override public String addStudent(Student student) { //業(yè)務(wù)方法 } }
注意事項:@Transactional
必須添加在public修飾的方法上。
2、全局事務(wù)(主要)
SpringBoot全局事務(wù)主要使用AOP切面編程。
第一步
創(chuàng)建切面類@Aspect
。
創(chuàng)建一個普通的類,加上@Aspect
后該類就是一個切面類了,用于編寫事務(wù)功能。
同時還需要把該切面類定義為一個配置類,添加注解@Configuration
即可。
注意事項:
1、@Aspect
將該類定義為切面類,把當前類作為一個切面被容器讀取。
? 2、@Configuration
將該類定義為配置類,配置spring容器,注入bean
package com.gx.config; import org.aspectj.lang.annotation.Aspect; import org.springframework.context.annotation.Configuration; @Aspect //定義切面類,把當前類標識為一個切面供容器讀取 @Configuration //定義配置類 public class TransactionAdviceConfig { //增強方法 }
第二步
創(chuàng)建第一個方法,返回事務(wù)攔截器(TransactionInterceptor),聲明業(yè)務(wù)方法的事務(wù)屬性,并且注冊到bean中。
需要返回事務(wù)攔截器TransactionInterceptor
,就需要new一個TransactionInterceptor
。
根據(jù)TransactionInterceptor
的類可得知,創(chuàng)建一個TransactionInterceptor
目前只有兩個方法。
public TransactionInterceptor() { } public TransactionInterceptor(TransactionManager ptm, TransactionAttributeSource tas) { this.setTransactionManager(ptm); this.setTransactionAttributeSource(tas); }
要使用事務(wù),就要有事務(wù)管理器TransactionManager
和事務(wù)屬性TransactionAttributeSource
。
配置事務(wù)屬性時一般都是通過方法的名字篩選,比如add*
、save*
、delete*
等,所以事務(wù)屬性使用的是他的子類NameMatchTransactionAttributeSource
。
//事務(wù)管理器 @Autowired private TransactionManager transactionManager; @Bean public TransactionInterceptor txAdvice() { //聲明一個通過方法名字配置事務(wù)屬性的對象 NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource(); //返回一個事務(wù)攔截器 return new TransactionInterceptor(transactionManager, source); }
通過方法名稱設(shè)置業(yè)務(wù)方法事務(wù)屬性。
NameMatchTransactionAttributeSource
類中我們使用的頻繁的就兩個方法。
setNameMap
其實就是addTransactionalMethod
的集合。
//通過map集合給多個方法或者多類方法設(shè)置事務(wù)屬性 public void setNameMap(Map<String, TransactionAttribute> nameMap) { nameMap.forEach(this::addTransactionalMethod); } //通過方法名稱或一類方法名稱和事務(wù)屬性,給一個方法或一類方法設(shè)置事務(wù)屬性 public void addTransactionalMethod(String methodName, TransactionAttribute attr) { if (logger.isDebugEnabled()) { logger.debug("Adding transactional method [" + methodName + "] with attribute [" + attr + "]"); } if (this.embeddedValueResolver != null && attr instanceof DefaultTransactionAttribute) { ((DefaultTransactionAttribute) attr).resolveAttributeStrings(this.embeddedValueResolver); } this.nameMap.put(methodName, attr); }
設(shè)置事務(wù)屬性。
TransactionAttribute
:事務(wù)屬性,有很多實現(xiàn)的實現(xiàn)類,一般使用基于規(guī)則的事務(wù)屬性RuleBasedTransactionAttribute
。
功能大部分在他的父類DefaultTransactionDefinition
中。
只寫一小部分,其他可以根據(jù)業(yè)務(wù)需求寫事務(wù)屬性。
//配置一個事務(wù)屬性(只讀) RuleBasedTransactionAttribute readOnlyTx = new RuleBasedTransactionAttribute(); //是否只讀 readOnlyTx.setReadOnly(true); //事務(wù)傳播行為 readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); //通過方法名稱設(shè)置業(yè)務(wù)方法事務(wù)屬性 Map<String, TransactionAttribute> txMap = new HashMap<>(); txMap.put("get*", readOnlyTx);
再添加到NameMatchTransactionAttributeSource
中
source.setNameMap(txMap);
設(shè)置事務(wù)屬性的方法
- 1、事務(wù)傳播行為 setPropagationBehavior();
- 2、事務(wù)隔離級別 setIsolationLevel();
- 3、事務(wù)超時時間 setTimeout();
- 4、事務(wù)只讀 setReadOnly();
- 5、設(shè)置事務(wù)名稱 setName();
- 6、設(shè)置回滾規(guī)則 setRollbackRules();
事務(wù)屬性。(擴展)
事務(wù)傳播行為
事務(wù)行為 | 說明 |
---|---|
PROPAGATION_REQUIRED | 支持當前事務(wù),假設(shè)當前沒有事務(wù)。就新建一個事務(wù) |
PROPAGATION_SUPPORTS | 支持當前事務(wù),假設(shè)當前沒有事務(wù),就以非事務(wù)方式運行 |
PROPAGATION_MANDATORY | 支持當前事務(wù),假設(shè)當前沒有事務(wù),就拋出異常 |
PROPAGATION_REQUIRES_NEW | 新建事務(wù),假設(shè)當前存在事務(wù)。把當前事務(wù)掛起 |
PROPAGATION_NOT_SUPPORTED | 以非事務(wù)方式運行操作。假設(shè)當前存在事務(wù),就把當前事務(wù)掛起 |
PROPAGATION_NEVER | 以非事務(wù)方式運行,假設(shè)當前存在事務(wù),則拋出異常 |
PROPAGATION_NESTED | 如果當前存在事務(wù),則在嵌套事務(wù)內(nèi)執(zhí)行。如果當前沒有事務(wù),則執(zhí)行與PROPAGATION_REQUIRED類似的操作。 |
事務(wù)隔離級別,事務(wù)的隔離級別只用4種但是spring提供有5種。(spring的隔離級別名字與數(shù)據(jù)庫中的不一樣)
隔離級別 | 說明 | 臟讀 | 幻讀 | 不可重復讀 |
---|---|---|---|---|
ISOLATION_DEFAULT | 默認隔離級別,每種數(shù)據(jù)庫支持的事務(wù)隔離級別不一樣,根據(jù)使用的數(shù)據(jù)庫改變。 | - | - | - |
ISOLATION_READ_UNCOMMITTED | 讀未提交,即能夠讀取到?jīng)]有被提交的數(shù)據(jù)。 | 是 | 是 | 是 |
ISOLATION_READ_COMMITTED | 讀已提交,即能夠讀到那些已經(jīng)提交的數(shù)據(jù)。 | 否 | 是 | 是 |
ISOLATION_REPEATABLE_READ | 重復讀取,即在數(shù)據(jù)讀出來之后加鎖。這個事務(wù)不結(jié)束,別的事務(wù)無法操作這條數(shù)據(jù)。 | 否 | 否 | 是 |
ISOLATION_SERIALIZABLE | 串行化,最高的事務(wù)隔離級別,不管多少事務(wù),挨個運行完一個事務(wù)的所有子事務(wù)之后才可以執(zhí)行另外一個事務(wù)里面的所有子事務(wù)。 | 否 | 否 | 否 |
第三步
配置適配器(Advisor),增強事務(wù)。
創(chuàng)建適配器(一個普通的方法返回Advisor)。
Advisor(顧問)是由切入點和Advice(通知)組成的,但是Advisor是一個接口,需要實現(xiàn)它實現(xiàn)類DefaultPointcutAdvisor
,并且傳入?yún)?shù)切入點和Adivce。
@Bean public Advisor txAdviceAdvisor() { //增強事務(wù),關(guān)聯(lián)切入點和事務(wù)屬性 return new DefaultPointcutAdvisor(切入點, Advice); }
配置切入點。
//配置切入點表達式 : 指定哪些包中的類使用事務(wù),設(shè)置為靜態(tài)類常量 private static final String AOP_POINTCUT_EXPRESSION = "execution (* com.***.service.*.*(..))"; //一下內(nèi)容放在適配器方法內(nèi) //配置事務(wù)切入點表達式 AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
關(guān)聯(lián)切入點和Advice。
//增強事務(wù),關(guān)聯(lián)切入點和事務(wù)屬性 return new DefaultPointcutAdvisor(pointcut, txAdvice());
第四步
重啟測試!
最后奉上aop全局事務(wù)全部代碼
package com.gx.config; import org.aspectj.lang.annotation.Aspect; import org.springframework.aop.Advisor; import org.springframework.aop.aspectj.AspectJExpressionPointcut; import org.springframework.aop.support.DefaultPointcutAdvisor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionManager; import org.springframework.transaction.interceptor.*; import javax.sql.DataSource; import java.util.Collections; import java.util.HashMap; import java.util.Map; @Aspect //定義切面類,把當前類標識為一個切面供容器讀取 @Configuration //定義配置類 public class TransactionAdviceConfig { //事務(wù)的超時時間為10秒 private static final int TX_METHOD_TIMEOUT = 10; //配置切入點表達式 : 指定哪些包中的類使用事務(wù) private static final String AOP_POINTCUT_EXPRESSION = "execution (* com.***.service.*.*(..))"; //事務(wù)管理器 @Autowired private TransactionManager transactionManager; /** * 聲明業(yè)務(wù)方法的事務(wù)屬性 */ @Bean public TransactionInterceptor txAdvice() { /** * 這里配置只讀事務(wù) */ RuleBasedTransactionAttribute readOnlyTx = new RuleBasedTransactionAttribute(); readOnlyTx.setReadOnly(true);//是否只讀 readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);//事務(wù)的傳播行為 /** * 必須帶事務(wù) * 當前存在事務(wù)就使用當前事務(wù),當前不存在事務(wù),就開啟一個新的事務(wù) */ RuleBasedTransactionAttribute requiredTx = new RuleBasedTransactionAttribute(); //檢查型異常也回滾 requiredTx.setRollbackRules( Collections.singletonList(new RollbackRuleAttribute(Exception.class))); requiredTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); requiredTx.setTimeout(TX_METHOD_TIMEOUT); /** * 無事務(wù)地執(zhí)行,掛起任何存在的事務(wù) */ RuleBasedTransactionAttribute noTx = new RuleBasedTransactionAttribute(); noTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED); /** * 設(shè)置方法對應(yīng)的事務(wù) */ Map<String, TransactionAttribute> txMap = new HashMap<>(); //只讀事務(wù) txMap.put("get*", readOnlyTx); txMap.put("query*", readOnlyTx); txMap.put("find*", readOnlyTx); txMap.put("list*", readOnlyTx); txMap.put("count*", readOnlyTx); txMap.put("exist*", readOnlyTx); txMap.put("search*", readOnlyTx); txMap.put("fetch*", readOnlyTx); //無事務(wù) txMap.put("noTx*", noTx); //寫事務(wù) txMap.put("add*", requiredTx); txMap.put("save*", requiredTx); txMap.put("insert*", requiredTx); txMap.put("update*", requiredTx); txMap.put("modify*", requiredTx); txMap.put("delete*", requiredTx); NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource(); source.setNameMap(txMap); //返回事務(wù)攔截器 return new TransactionInterceptor(transactionManager, source); } @Bean public Advisor txAdviceAdvisor() { //配置事務(wù)切入點表達式 AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); pointcut.setExpression(AOP_POINTCUT_EXPRESSION); //增強事務(wù),關(guān)聯(lián)切入點和事務(wù)屬性 return new DefaultPointcutAdvisor(pointcut, txAdvice()); } }
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Freemaker Replace函數(shù)的正則表達式運用
這篇文章主要介紹了Freemaker Replace函數(shù)的正則表達式運用 的相關(guān)資料,需要的朋友可以參考下2015-12-12解決IDEA2020.1.2IDEA打不開的問題(最新分享)
由于idea安裝多了某個jar,點擊出現(xiàn)讀條后閃退情況,接下來通過本文給大家分享解決IDEA2020.1.2IDEA打不開的問題,非常不錯,具有一定的參考借鑒價值,感興趣的朋友跟隨小編一起看看吧2020-07-07基于Java快速實現(xiàn)一個簡單版的HashMap詳解
這篇文章主要為大家詳細介紹了如何利用Java簡單實現(xiàn)一個底層數(shù)據(jù)結(jié)構(gòu)為數(shù)組?+?鏈表的HashMap,不考慮鏈表長度超過8個時變?yōu)榧t黑樹的情況,需要的可以參考一下2023-02-02JAVAWEB實現(xiàn)簡單的商城項目(一)實例代碼解析
本文給大家分享一段實例代碼給大家介紹JAVAWEB實現(xiàn)簡單的商城項目(一),非常具有參考價值,感興趣的朋友一起學習吧2016-02-02使用SpringBoot開發(fā)Restful服務(wù)實現(xiàn)增刪改查功能
Spring Boot是由Pivotal團隊提供的全新框架,其設(shè)計目的是用來簡化新Spring應(yīng)用的初始搭建以及開發(fā)過程。這篇文章主要介紹了基于SpringBoot開發(fā)一個Restful服務(wù),實現(xiàn)增刪改查功能,需要的朋友可以參考下2018-01-01