Spring詳細解讀事務(wù)管理
什么是事務(wù)
事務(wù)就是對數(shù)據(jù)庫若干操作組成的一個單元
我們在開發(fā)企業(yè)應(yīng)用時,對于業(yè)務(wù)人員的一個操作實際是對數(shù)據(jù)讀寫的多步操作的結(jié)合。由于數(shù)據(jù)操作在順序執(zhí)行的過程中,任何一步操作都有可能發(fā)生異常,異常會導(dǎo)致后續(xù)操作無法完成,此時由于業(yè)務(wù)邏輯并未正確的完成,之前成功操作數(shù)據(jù)的并不可靠,需要在這種情況下進行回退
事務(wù)的作用就是為了保證用戶的每一個操作都是可靠的,事務(wù)中的每一步操作都必須成功執(zhí)行,只要有發(fā)生異常就回退到事務(wù)開始未進行操作的狀態(tài),這些操作要么都完成,要么都取消,從而保證數(shù)據(jù)滿足一致性的要求
如何理解呢 ?
例如 : A現(xiàn)在要轉(zhuǎn)賬給B 那么轉(zhuǎn)賬是幾個方法呢? 兩個 : 方法1: A 減錢 方法2: B加錢
如果A方法成功執(zhí)行后 , B方法中執(zhí)行時出現(xiàn)了異常, 就等于A錢扣了卻沒有給B加錢, 那么這樣的行為肯定是不允許的, 所以我們引入事務(wù)的概念 , 事務(wù)一般也是對于數(shù)據(jù)庫而言的
Spring事務(wù)配置
Spring事務(wù)管理又分為編程式事務(wù)和聲明式事務(wù)
編 程 式 事 務(wù) 在 項 目 中 很 少 使 用 , 這 種 方 式 需 要 注 入 一 個 事 務(wù) 管 理 對 象 TransactionTemplate ,然后在我們代碼中需要提交事務(wù)或回滾事務(wù)時自己寫代碼實現(xiàn)
聲明式事務(wù)管理建立在 AOP 基礎(chǔ)上,本質(zhì)是對方法前后進行攔截,所以聲明式事務(wù)是方法級別的。
為什么說是基于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>
基于注解的方式直接幫我們省略了這個過程, 更為方便
這里我們主要介紹聲明式事務(wù)
首先在db.xml中配置spring事務(wù)管理類
<!--配置spring事務(wù)管理類-->
<bean id="sourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="druidDataSource"/>
</bean>這里我們直接介紹基于注解方式的spring事務(wù)管理
開啟注解掃描
<!-- 開啟注解事務(wù)管理 --> <tx:annotation-driven transaction-manager="sourcetransactionManager"/>
我們使用@Transactiona 這樣一個注解標(biāo)簽來聲明事務(wù), 它可以作用于方法,表明這個方法支持事務(wù), 也可以作用于類, 表明這個類中的所有方法支持事務(wù)
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; //出現(xiàn)異常
jdbcTemplate.update("insert into admin(account,pass_word,sex) values (?,?,?)","qw","111","男");
}
}在上述代碼中, 第一條sql 語句雖然成功執(zhí)行, 但后面出現(xiàn)了異常, 所以這個方法的事務(wù)并沒有提交, 是不會向數(shù)據(jù)庫提交數(shù)據(jù)的
Spring事務(wù)傳播行為
即然是傳播,那么至少有兩個東西,才可以發(fā)生傳播。單體不存在傳播這個行為。事務(wù)傳播行為(propagation behavior)指的就是當(dāng)一個事務(wù)方法被另一個事務(wù)方法調(diào)用時,這個事務(wù)方法應(yīng)該如何進行。事務(wù)傳播行為是 Spring 框架獨有的事務(wù)增強特性,他不屬于的事務(wù)實際提供方數(shù)據(jù)庫行為.
是不是有點懵, 說啥呢這是, 接著來解釋
試想 , 有兩個方法 A 和 B , 它們都有事務(wù), 那么我在 A 方法中去調(diào)用 B 方法, 那么B方法此時
應(yīng)該怎樣去執(zhí)行呢? 是將B 方法加入到 A 方法組成一個事務(wù),還是它們都是一個獨立的事務(wù)呢 ?
Spring定義了 7種 事務(wù)傳播行為, 我們下面主要介紹其中三種,都會舉例說明
傳播行為一般是對于B方法(被調(diào)用的方法而言的)
1. PROPAGATION_REQUIRED
指定的方法必須在事務(wù)內(nèi)執(zhí)行,若當(dāng)前存在事務(wù),加入到當(dāng)前事務(wù)中,若當(dāng)前沒有事務(wù),則創(chuàng)建一個新事務(wù),這種傳播行為是最常見的,也是 spring 默認的傳播行為
A 方法調(diào)用 B方法(PROPAGATION_REQUIRED) , 如果A方法是存在事務(wù)的, 那么直接將B方
法加入到 A事務(wù)中,組成一個事務(wù). 如果 A 方法是沒有事務(wù)的, 那么B就是一個單獨的事務(wù)
這么說可能有點繞 , 我們再次請出李雷, 算了, 這次就放過李雷, 換成張三吧
就是說呢 , 我和李雷現(xiàn)在都要去吃飯, 然后我說呢,李雷咱倆一起吧(A調(diào)用B,我叫李雷去吃飯) , 不出意外的話(事務(wù)順利執(zhí)行提交), 我們兩吃飯作為一個整體, 最終都吃了飯(AB都存在事務(wù)就作為一個整體事務(wù)) , 但是還有一種情況, 我叫李雷去吃飯, 但是我卻沒有去(A調(diào)用B, 但是A沒有事務(wù)),那么這時候李雷肯定單獨去吃飯(B單獨開啟一個事務(wù))
@Transactional(propagation = Propagation.REQUIRED)
public void saveDept(){ //A調(diào)用B
deptDao.saveDept();
commonService.saveLog(); //B
}@Transactional(propagation = Propagation.REQUIRED)
public void saveLog(){
commonDao.saveLog();
int a = 10/0; //異常
}此時 A 調(diào)用 B , 它們都有事務(wù), B中出了異常, 那么此時AB最終都不會去和數(shù)據(jù)庫交互
//@Transactional(propagation = Propagation.REQUIRED)
public void saveDept(){ //A調(diào)用B
deptDao.saveDept();
commonService.saveLog(); //B
}@Transactional(propagation = Propagation.REQUIRED)
public void saveLog(){
commonDao.saveLog();
int a = 10/0; //異常
}第二種方式 , 我們將異常加到A 中, 注釋掉注解(取消A的事務(wù)), 那么此時B是單獨的一個事務(wù), B里面出了異常, 不會去和數(shù)據(jù)庫交互, 則A會去和數(shù)據(jù)庫交互
2. PROPAGATION_SUPPORTS
支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就以非事務(wù)方式執(zhí)行
A方法調(diào)用B方法(PROPAGATION_SUPPORTS), 如果A是存在事務(wù)的,那么直接將B方
法加入到 A事務(wù)中,組成一個事務(wù). 如果 A 沒有事務(wù), 那么B也沒有事務(wù)
我叫李雷去吃飯 , 如果我一定要去吃飯(A調(diào)用B), 那么最終我吃飯和李雷吃飯就總共作為一個事務(wù),就和上面第一個例子是一樣的, 作為整體的一個事務(wù). 但是第二種情況就是, 我雖然叫了李雷去吃飯, 但是我最終沒有去(A沒有事務(wù)) , 這時候李雷說, 那我也不去吃飯了(B也沒有事務(wù))
@Transactional(propagation = Propagation.REQUIRED)
public void saveDept(){ //A調(diào)用B
deptDao.saveDept();
commonService.saveLog(); //B
}@Transactional(propagation = Propagation.SUPPORTS)
public void saveLog(){
commonDao.saveLog();
int a = 10/0; //異常
}此時 A調(diào)用 B , AB都有事務(wù), 那么B 中出現(xiàn)異常, 最終都不會和數(shù)據(jù)庫交互,就和上述第一種情況
一樣
//@Transactional(propagation = Propagation.REQUIRED)
public void saveDept(){ //A調(diào)用B
deptDao.saveDept();
commonService.saveLog(); //B
}取消掉A 的事務(wù) , 那么此時B 會以非事務(wù)執(zhí)行 , 這時候AB都會和數(shù)據(jù)庫去交互,因為非事務(wù)
3. PROPAGATION_REQUIRES_NEW
總是新建一個事務(wù),如果當(dāng)前存在事務(wù),把當(dāng)前事務(wù)掛起,直到新建的事務(wù)結(jié)束。
A方法調(diào)用B方法(PROPAGATION_REQUIRES_NEW), 如果A存在事務(wù), 那么B此時會先把A事務(wù)掛起, 然后為自己新建一個事務(wù), 先執(zhí)行完B事務(wù), 才會去執(zhí)行 A 事務(wù) . 如果A 沒有事務(wù), 那么B自己單獨新建一個事務(wù)執(zhí)行
這里就是, 我雖然叫李雷去吃飯(A調(diào)用B) , 李雷都會先自己去吃飯, 不等我(B自己新建一個事務(wù), A有事務(wù)先將A掛起)
@Transactional(propagation = Propagation.REQUIRED)
public void saveDept(){ //A調(diào)用B
deptDao.saveDept();
commonService.saveLog(); //B
}@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveLog(){
commonDao.saveLog();
int a = 10/0; //異常
}A 調(diào)用 B , A支持事務(wù) , 此時B將A事務(wù)掛起, 單獨開啟一個事務(wù),里面出現(xiàn)異常,此時AB都不會和數(shù)據(jù)庫交互
//@Transactional(propagation = Propagation.REQUIRED)
public void saveDept(){ //A調(diào)用B
deptDao.saveDept();
commonService.saveLog(); //B
}取消A的事務(wù), 但此時B事務(wù)是獨立的, 出現(xiàn)異常, 所以B不會和數(shù)據(jù)庫交互,但是A和數(shù)據(jù)庫交互
聲明式事務(wù)失效
事務(wù)也是會失效的 , 失效有以下幾種情況
1.@Transactional 應(yīng)用在非 public 修飾的方法上
2.@Transactional 注解屬性 propagation 設(shè)置錯誤
3.同一個類中方法調(diào)用,導(dǎo)致@Transactional 失效
4.異常被 catch 捕獲導(dǎo)致@Transactional 失效
5.數(shù)據(jù)庫引擎不支持事務(wù)
非public修飾導(dǎo)致權(quán)限錯誤, 事務(wù)失效, propagation設(shè)置參數(shù)錯誤導(dǎo)致事務(wù)失效
同類下方法調(diào)用也會導(dǎo)致事務(wù)失效
catch如果捕獲了異常, 就相當(dāng)于程序沒有異常,這時事務(wù)也會失效
最后就是數(shù)據(jù)庫引擎不支持, mysql中只有InnoDB引擎是支持事務(wù)的
結(jié)語
關(guān)于Spring 事務(wù)管理就先說到這 , 后面介紹SpringMVC 與 ssm 框架, 謝謝,愛你們??學(xué) spring 一定要笑, 笑著學(xué) ,嘿嘿
到此這篇關(guān)于Spring詳細解讀事務(wù)管理的文章就介紹到這了,更多相關(guān)Spring事務(wù)管理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Springboot下使用Redis管道(pipeline)進行批量操作
本文主要介紹了Spring?boot?下使用Redis管道(pipeline)進行批量操作,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05

