SpringBoot中的聲明式事務+切面事務+編程式事務詳解
前言
事務管理對于企業(yè)應用來說是至關重要的,當出現(xiàn)異常情況時,它也可以保證數(shù)據(jù)的一致性。
springBoot中兩種事務的實現(xiàn)方式,編程式事務配置和聲明式事務配置還有切面事務 還有以后的分布式事務
一、事務特性
- 原子性(Atomicity):
- 事務是一個原子操作,由一系列動作組成。事務的原子性確保動作要么全部完成,要么完全不起作用;
- 一致性(Consistency):
- 一旦事務完成(不管是成功還是失敗),系統(tǒng)必須確保它所建模的業(yè)務處于一致的狀態(tài),而不會是部分完成部分失敗。在現(xiàn)實中的數(shù)據(jù)不應該被破壞;
- 隔離性(Isolation):
- 可能有許多事務會同時處理相同的數(shù)據(jù),因此每個事務都應該與其他事務隔離開來,防止數(shù)據(jù)損壞;
- 持久性(Durability):
- 一旦事務完成,無論發(fā)生什么系統(tǒng)錯誤,它的結(jié)果都不應該受到影響,這樣就能從任何系統(tǒng)崩潰中恢復過來。通常情況下,事務的結(jié)果被寫到持久化存儲器中;
Spring 框架中,涉及到事務管理的 API 大約有100個左右,其中最重要的有三個: TransactionDefinition、PlatformTransactionManager、TransactionStatus
。
所謂事務管理,其實就是”按照給定的事務規(guī)則來執(zhí)行提交或者回滾操作”。”
給定的事務規(guī)則”就是用 TransactionDefinition 表示的,”按照……來執(zhí)行提交或者回滾操作”便是用 PlatformTransactionManager 來表示
而 TransactionStatus 用于表示一個運行著的事務的狀態(tài)。
打一個不恰當?shù)谋扔?,TransactionDefinition 與 TransactionStatus 的關系就像程序和進程的關系。
開啟事務 @EnableTransactionManagement
二、事務的隔離級別
和數(shù)據(jù)庫中的事務級別是一樣的 都會出現(xiàn)事務本身應該有的問題
三、事務的傳播行為
四、 Springboot事務
1.Springboot聲明式事務
聲明式事務是建立在AOP之上的。
其本質(zhì)是對方法前后進行攔截,然后在目標方法開始之前創(chuàng)建或者加入一個事務,在執(zhí)行完目標方法之后根據(jù)執(zhí)行情況提交或者回滾事務。
Spring配置文件中關于事務配置總是由三個組成部分,分別是DataSource、TransactionManager和代理機制這三部分,無論哪種配置方式,一般變化的只是代理機制這部分。
DataSource、TransactionManager這兩部分只是會根據(jù)數(shù)據(jù)訪問方式有所變化,比如使用Hibernate進行數(shù)據(jù)訪問時,DataSource實際為SessionFactory,TransactionManager的實現(xiàn)為HibernateTransactionManager。
根據(jù)代理機制的不同,總結(jié)了五種Spring事務的配置方式,如下圖:
聲明式事務@Transactional可以使用在類上,也可以使用在public方法上
如果是使用在類上,則是對所有的public方法都開啟事務,如果類和方法上都有則方法上的事務生效
在類上
@Transactional(rollbackFor=Exception.class) public class TransactionServiceImpl implements TransactionService { }
在方法上
@Override @Transactional(rollbackFor=Exception.class) public void t1(Student one) { }
聲明式事務最大的優(yōu)點就是不需要通過編程的方式管理事務,這樣就不需要在業(yè)務邏輯代碼中摻雜事務管理的代碼,只需在配置文件中做相關的事務規(guī)則聲明(或通過基于@Transactional注解的方式),便可以將事務規(guī)則應用到業(yè)務邏輯中。
優(yōu)點:
編程式事務每次實現(xiàn)都要單獨實現(xiàn),但業(yè)務量大且功能復雜時,使用編程性事務無疑是痛苦的;而聲明式事務不同,聲明式事務屬于非侵入性,不會影響業(yè)務邏輯的實現(xiàn),只需在配置文件中做相關的事務規(guī)則聲明(或通過基于@Transactional注解的方式),便可以將事務規(guī)則應用到業(yè)務邏輯中;
非侵入式的開發(fā)方式,聲明式事務管理使業(yè)務代碼不受污染,一個普通的POJO對象,只要加上注解就可以獲得完全的事務支持;
缺點:
最細粒度只能是作用到方法級別,無法做到像編程事務那樣可以作用到代碼塊級別;
實現(xiàn)方式:
使用攔截器:基于TransactionInterceptor 類來實施聲明式事務管理功能(Spring最初提供的實現(xiàn)方式);
Bean和代理:基于 TransactionProxyFactoryBean的聲明式事務管理
使用tx標簽配置的攔截器:基于tx和aop名字空間的xml配置文件(基于Aspectj AOP配置事務); 全注解:基于@Transactional注解;
@Transactional的參數(shù)
聲明式事務的約定流程:
首先Spring通過事務管理器(PlatformTransactionManager的子類)創(chuàng)建事務,與此同時會把事務定義中的隔離級別、超時時間等屬性根據(jù)配置內(nèi)容往事務上設置。
而根據(jù)傳播行為配置采取一種特定的策略,后面會談到傳播行為的使用問題,這是Spring根據(jù)配置完成的內(nèi)容,你只需要配置,無須編碼。
然后,啟動開發(fā)者提供的業(yè)務代碼,我們知道Spring會通過反射的方式調(diào)度開發(fā)者的業(yè)務代碼,但是反射的結(jié)果可能是正常返回或者產(chǎn)生異常返回,那么它給的約定是只要發(fā)生異常,并且符合事務定義類回滾條件的,Spring就會將數(shù)據(jù)庫事務回滾,否則將數(shù)據(jù)庫事務提交,這也是Spring自己完成的
顯然聲明式事務管理要優(yōu)于編程式事務管理,這正是spring倡導的非侵入式的開發(fā)方式。
聲明式事務管理使業(yè)務代碼不受污染,一個普通的POJO對象,只要加上注解就可以獲得完全的事務支持。和編程式事務相比,聲明式事務唯一不足地方是,它的最細粒度只能作用到方法級別,無法做到像編程式事務那樣可以作用到代碼塊級別。
但是即便有這樣的需求,也存在很多變通的方法,比如,可以將需要進行事務管理的代碼塊獨立為方法等等。
聲明式事務管理也有兩種常用的方式,一種是基于tx和aop名字空間的xml配置文件,另一種就是基于@Transactional注解。
顯然基于注解的方式更簡單易用,更清爽。
2. Springboot編程式事務
編程式事務: 是侵入性事務管理,直接使用底層的PlatformTransactionManager、使用TransactionTemplate(Spring推薦使用);
編程式事務管理對基于 POJO 的應用來說是唯一選擇。
我們需要在代碼中調(diào)用beginTransaction()、commit()、rollback()等事務管理相關的方法;
@Autowired private TransactionTemplate transactionTemplate;
@Override public final void save2() { transactionTemplate.execute((status)->{ mapper.saveStudent(newOne()); mapper.saveStudent(newOne()); return Boolean.TRUE; }); }
這樣兩個mapper.saveStudent(newOne());就在一個事務中執(zhí)行了
3.SpringBoo切面編程式事務
SpringBoo切面編程式事務應該是聲明式事務的一種具體體現(xiàn) 此種方式基于AOP功能,所以需要添加
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
配置類
@Aspect @Configuration public class MyTransactionConfig { /** * 配置方法過期時間,默認-1,永不超時 */ private final static int TX_METHOD_TIME_OUT = 10; /** * 全局事務位置配置 在哪些地方需要進行事務處理 * 配置切入點表達式 */ private static final String POITCUT_EXPRESSION = "execution(* zdc.enterprise.service.impl.*.*(..))"; @Autowired private PlatformTransactionManager platformTransactionManager; @Bean public TransactionInterceptor txadvice() { /*只讀事物、不做更新刪除等*/ /*事務管理規(guī)則*/ RuleBasedTransactionAttribute readOnlyRule = new RuleBasedTransactionAttribute(); /*設置當前事務是否為只讀事務,true為只讀*/ readOnlyRule.setReadOnly(true); /* transactiondefinition 定義事務的隔離級別; *如果當前存在事務,則加入該事務;如果當前沒有事務,則以非事務的方式繼續(xù)運行。*/ readOnlyRule.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS); /*增刪改事務規(guī)則*/ RuleBasedTransactionAttribute requireRule = new RuleBasedTransactionAttribute(); /*拋出異常后執(zhí)行切點回滾 建議自定義異常*/ requireRule.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class))); /*PROPAGATION_REQUIRED:事務隔離性為1,若當前存在事務,則加入該事務;如果當前沒有事務,則創(chuàng)建一個新的事務。這是默認值。 */ requireRule.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); /*設置事務失效時間,超過10秒*/ requireRule.setTimeout(TX_METHOD_TIME_OUT); /** 配置事務管理規(guī)則 nameMap聲明具備需要管理事務的方法名. 這里使用addTransactionalMethod 使用setNameMap */ Map<String, TransactionAttribute> nameMap = new HashMap<>(); nameMap.put("add*", requireRule); nameMap.put("save*", requireRule); nameMap.put("insert*", requireRule); nameMap.put("update*", requireRule); nameMap.put("delete*", requireRule); nameMap.put("remove*", requireRule); /*進行批量操作時*/ nameMap.put("batch*", requireRule); nameMap.put("get*", readOnlyRule); nameMap.put("query*", readOnlyRule); nameMap.put("find*", readOnlyRule); nameMap.put("select*", readOnlyRule); nameMap.put("count*", readOnlyRule); NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource(); source.setNameMap(nameMap); TransactionInterceptor transactionInterceptor = new TransactionInterceptor(platformTransactionManager, source); return transactionInterceptor; } /** * 設置切面=切點pointcut+通知TxAdvice * @return */ @Bean public Advisor txAdviceAdvisor() { AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); pointcut.setExpression(POITCUT_EXPRESSION); return new DefaultPointcutAdvisor(pointcut, txadvice()); } }
有了這個切面配置類,就不要用在類或者每個方法上使用@Transactional了,當然方法名前綴要能和設置的匹配上
RuleBasedTransactionAttribute的參數(shù)大致和@Transactional的參數(shù)相同,里面有詳細的注釋,就不過多解釋了
到此這篇關于SpringBoot中的聲明式事務+切面事務+編程式事務詳解的文章就介紹到這了,更多相關SpringBoot各類型事務內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java多線程中線程的兩種創(chuàng)建方式及比較代碼示例
這篇文章主要介紹了Java多線程中線程的兩種創(chuàng)建方式及比較代碼示例,簡單介紹了線程的概念,并行與并發(fā)等,然后通過實例代碼向大家展示了線程的創(chuàng)建,具有一定參考價值,需要的朋友可以了解下。2017-11-11Springboot中路徑參數(shù)帶 (%2F)的問題徹底解決方案
這篇文章主要介紹了徹底解決Springboot中路徑參數(shù)帶(%2F)的問題,本文結(jié)合示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-06-06logback StatusListener的定義方法源碼解讀
這篇文章主要為大家介紹了logback StatusListener的定義方法源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-11-11