Spring詳細解讀事務管理
什么是事務
事務就是對數據庫若干操作組成的一個單元
我們在開發(fā)企業(yè)應用時,對于業(yè)務人員的一個操作實際是對數據讀寫的多步操作的結合。由于數據操作在順序執(zhí)行的過程中,任何一步操作都有可能發(fā)生異常,異常會導致后續(xù)操作無法完成,此時由于業(yè)務邏輯并未正確的完成,之前成功操作數據的并不可靠,需要在這種情況下進行回退
事務的作用就是為了保證用戶的每一個操作都是可靠的,事務中的每一步操作都必須成功執(zhí)行,只要有發(fā)生異常就回退到事務開始未進行操作的狀態(tài),這些操作要么都完成,要么都取消,從而保證數據滿足一致性的要求
如何理解呢 ?
例如 : A現在要轉賬給B 那么轉賬是幾個方法呢? 兩個 : 方法1: A 減錢 方法2: B加錢
如果A方法成功執(zhí)行后 , B方法中執(zhí)行時出現了異常, 就等于A錢扣了卻沒有給B加錢, 那么這樣的行為肯定是不允許的, 所以我們引入事務的概念 , 事務一般也是對于數據庫而言的
Spring事務配置
Spring事務管理又分為編程式事務和聲明式事務
編 程 式 事 務 在 項 目 中 很 少 使 用 , 這 種 方 式 需 要 注 入 一 個 事 務 管 理 對 象 TransactionTemplate ,然后在我們代碼中需要提交事務或回滾事務時自己寫代碼實現
聲明式事務管理建立在 AOP 基礎上,本質是對方法前后進行攔截,所以聲明式事務是方法級別的。
為什么說是基于AOP呢? 因為在通過xml文件配置中我們是這樣來做的
<aop:config> <aop:pointcut expression="execution(* com.ff.spring.service.UserService.*(..))" id="allmethod"/> <aop:advisor advice-ref="txadvice" pointcut-ref="allmethod"/> </aop:config>
基于注解的方式直接幫我們省略了這個過程, 更為方便
這里我們主要介紹聲明式事務
首先在db.xml中配置spring事務管理類
<!--配置spring事務管理類-->
<bean id="sourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="druidDataSource"/>
</bean>這里我們直接介紹基于注解方式的spring事務管理
開啟注解掃描
<!-- 開啟注解事務管理 --> <tx:annotation-driven transaction-manager="sourcetransactionManager"/>
我們使用@Transactiona 這樣一個注解標簽來聲明事務, 它可以作用于方法,表明這個方法支持事務, 也可以作用于類, 表明這個類中的所有方法支持事務
public class UserDao {
@Autowired
JdbcTemplate jdbcTemplate;
@Transactional(propagation= Propagation.REQUIRED)
public void saveUser(){
jdbcTemplate.update("insert into admin(account,pass_word,sex) values (?,?,?)","li","111","男");
int i=108/0; //出現異常
jdbcTemplate.update("insert into admin(account,pass_word,sex) values (?,?,?)","qw","111","男");
}
}在上述代碼中, 第一條sql 語句雖然成功執(zhí)行, 但后面出現了異常, 所以這個方法的事務并沒有提交, 是不會向數據庫提交數據的
Spring事務傳播行為
即然是傳播,那么至少有兩個東西,才可以發(fā)生傳播。單體不存在傳播這個行為。事務傳播行為(propagation behavior)指的就是當一個事務方法被另一個事務方法調用時,這個事務方法應該如何進行。事務傳播行為是 Spring 框架獨有的事務增強特性,他不屬于的事務實際提供方數據庫行為.
是不是有點懵, 說啥呢這是, 接著來解釋
試想 , 有兩個方法 A 和 B , 它們都有事務, 那么我在 A 方法中去調用 B 方法, 那么B方法此時
應該怎樣去執(zhí)行呢? 是將B 方法加入到 A 方法組成一個事務,還是它們都是一個獨立的事務呢 ?
Spring定義了 7種 事務傳播行為, 我們下面主要介紹其中三種,都會舉例說明
傳播行為一般是對于B方法(被調用的方法而言的)
1. PROPAGATION_REQUIRED
指定的方法必須在事務內執(zhí)行,若當前存在事務,加入到當前事務中,若當前沒有事務,則創(chuàng)建一個新事務,這種傳播行為是最常見的,也是 spring 默認的傳播行為
A 方法調用 B方法(PROPAGATION_REQUIRED) , 如果A方法是存在事務的, 那么直接將B方
法加入到 A事務中,組成一個事務. 如果 A 方法是沒有事務的, 那么B就是一個單獨的事務
這么說可能有點繞 , 我們再次請出李雷, 算了, 這次就放過李雷, 換成張三吧
就是說呢 , 我和李雷現在都要去吃飯, 然后我說呢,李雷咱倆一起吧(A調用B,我叫李雷去吃飯) , 不出意外的話(事務順利執(zhí)行提交), 我們兩吃飯作為一個整體, 最終都吃了飯(AB都存在事務就作為一個整體事務) , 但是還有一種情況, 我叫李雷去吃飯, 但是我卻沒有去(A調用B, 但是A沒有事務),那么這時候李雷肯定單獨去吃飯(B單獨開啟一個事務)
@Transactional(propagation = Propagation.REQUIRED)
public void saveDept(){ //A調用B
deptDao.saveDept();
commonService.saveLog(); //B
}@Transactional(propagation = Propagation.REQUIRED)
public void saveLog(){
commonDao.saveLog();
int a = 10/0; //異常
}此時 A 調用 B , 它們都有事務, B中出了異常, 那么此時AB最終都不會去和數據庫交互
//@Transactional(propagation = Propagation.REQUIRED)
public void saveDept(){ //A調用B
deptDao.saveDept();
commonService.saveLog(); //B
}@Transactional(propagation = Propagation.REQUIRED)
public void saveLog(){
commonDao.saveLog();
int a = 10/0; //異常
}第二種方式 , 我們將異常加到A 中, 注釋掉注解(取消A的事務), 那么此時B是單獨的一個事務, B里面出了異常, 不會去和數據庫交互, 則A會去和數據庫交互
2. PROPAGATION_SUPPORTS
支持當前事務,如果當前沒有事務,就以非事務方式執(zhí)行
A方法調用B方法(PROPAGATION_SUPPORTS), 如果A是存在事務的,那么直接將B方
法加入到 A事務中,組成一個事務. 如果 A 沒有事務, 那么B也沒有事務
我叫李雷去吃飯 , 如果我一定要去吃飯(A調用B), 那么最終我吃飯和李雷吃飯就總共作為一個事務,就和上面第一個例子是一樣的, 作為整體的一個事務. 但是第二種情況就是, 我雖然叫了李雷去吃飯, 但是我最終沒有去(A沒有事務) , 這時候李雷說, 那我也不去吃飯了(B也沒有事務)
@Transactional(propagation = Propagation.REQUIRED)
public void saveDept(){ //A調用B
deptDao.saveDept();
commonService.saveLog(); //B
}@Transactional(propagation = Propagation.SUPPORTS)
public void saveLog(){
commonDao.saveLog();
int a = 10/0; //異常
}此時 A調用 B , AB都有事務, 那么B 中出現異常, 最終都不會和數據庫交互,就和上述第一種情況
一樣
//@Transactional(propagation = Propagation.REQUIRED)
public void saveDept(){ //A調用B
deptDao.saveDept();
commonService.saveLog(); //B
}取消掉A 的事務 , 那么此時B 會以非事務執(zhí)行 , 這時候AB都會和數據庫去交互,因為非事務
3. PROPAGATION_REQUIRES_NEW
總是新建一個事務,如果當前存在事務,把當前事務掛起,直到新建的事務結束。
A方法調用B方法(PROPAGATION_REQUIRES_NEW), 如果A存在事務, 那么B此時會先把A事務掛起, 然后為自己新建一個事務, 先執(zhí)行完B事務, 才會去執(zhí)行 A 事務 . 如果A 沒有事務, 那么B自己單獨新建一個事務執(zhí)行
這里就是, 我雖然叫李雷去吃飯(A調用B) , 李雷都會先自己去吃飯, 不等我(B自己新建一個事務, A有事務先將A掛起)
@Transactional(propagation = Propagation.REQUIRED)
public void saveDept(){ //A調用B
deptDao.saveDept();
commonService.saveLog(); //B
}@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveLog(){
commonDao.saveLog();
int a = 10/0; //異常
}A 調用 B , A支持事務 , 此時B將A事務掛起, 單獨開啟一個事務,里面出現異常,此時AB都不會和數據庫交互
//@Transactional(propagation = Propagation.REQUIRED)
public void saveDept(){ //A調用B
deptDao.saveDept();
commonService.saveLog(); //B
}取消A的事務, 但此時B事務是獨立的, 出現異常, 所以B不會和數據庫交互,但是A和數據庫交互
聲明式事務失效
事務也是會失效的 , 失效有以下幾種情況
1.@Transactional 應用在非 public 修飾的方法上
2.@Transactional 注解屬性 propagation 設置錯誤
3.同一個類中方法調用,導致@Transactional 失效
4.異常被 catch 捕獲導致@Transactional 失效
5.數據庫引擎不支持事務
非public修飾導致權限錯誤, 事務失效, propagation設置參數錯誤導致事務失效
同類下方法調用也會導致事務失效
catch如果捕獲了異常, 就相當于程序沒有異常,這時事務也會失效
最后就是數據庫引擎不支持, mysql中只有InnoDB引擎是支持事務的
結語
關于Spring 事務管理就先說到這 , 后面介紹SpringMVC 與 ssm 框架, 謝謝,愛你們??學 spring 一定要笑, 笑著學 ,嘿嘿
到此這篇關于Spring詳細解讀事務管理的文章就介紹到這了,更多相關Spring事務管理內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
淺談MultipartFile中transferTo方法的坑
這篇文章主要介紹了MultipartFile中transferTo方法的坑,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07
Springboot?整合maven插口調用maven?release?plugin實現一鍵打包功能
這篇文章主要介紹了Springboot?整合maven插口調用maven?release?plugin實現一鍵打包功能,整合maven-invoker使程序去執(zhí)行mvn命令,結合示例代碼給大家介紹的非常詳細,需要的朋友可以參考下2022-03-03
Mybatis執(zhí)行Update返回行數為負數的問題
這篇文章主要介紹了Mybatis執(zhí)行Update返回行數為負數的問題,具有很好的參考價值,希望大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12
PostMan如何傳參給@RequestBody(接受前端參數)
這篇文章主要介紹了PostMan如何傳參給@RequestBody(接受前端參數),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10
Spring Boot + Mybatis 實現動態(tài)數據源案例分析
這篇文章主要介紹了Spring Boot + Mybatis 實現動態(tài)數據源,需要的朋友可以參考下2018-11-11
使用Jacoco獲取 Java 程序的代碼執(zhí)行覆蓋率的步驟詳解
這篇文章主要介紹了使用Jacoco獲取 Java 程序的代碼執(zhí)行覆蓋率的步驟詳解,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下2021-03-03

