javascript
SpringBoot声明式事务
目錄
- 事務的基本特征
- 隔離級別
- 傳播行為
- @Transcation
事務的基本特征(ACID)
Atomic(原子性)
事務中包含的操作被看作一個整體的業(yè)務單元,這個業(yè)務單元中的操作要么全部成功,要么全部失敗,不會出現(xiàn)部分失敗和部分成功的場景
Consistency(一致性)
事務在完成時,必須使所有的數(shù)據(jù)都保持一直狀態(tài),在數(shù)據(jù)庫中所有的修改都基于事務,保證了數(shù)據(jù)的完整性
Isolation(隔離性)
多個應用程序線程同時訪問統(tǒng)一數(shù)據(jù),這樣數(shù)據(jù)庫同樣的數(shù)據(jù)就會在各個不同的事務中被訪問,這樣會產(chǎn)生丟失更新,為了壓制丟失更新的產(chǎn)生,數(shù)據(jù)庫定義了隔離級別的概念,通過它的選擇,可以在不同程度上壓制丟失更新的產(chǎn)生。因為互聯(lián)網(wǎng)的應用常常面對高并發(fā)的場景,所以隔離性是需要掌握的重點內(nèi)容
Durability(持久性)
事務結(jié)束后,所有的數(shù)據(jù)都會固化到一個地方,如保存磁盤當中,即時斷電重啟后也可以提供應用程序訪問
為了壓制丟失更新,數(shù)據(jù)庫提出了隔離級別,在不同程度上壓制更新
也許會有一個疑問,都全部消除丟失更新不就好了嗎,為什么只是在不同的程度.上壓制丟失更新呢?
其實這個問題是從兩個角度去看的,一個是數(shù)據(jù)的一致性,另一個是性能。數(shù)據(jù)庫現(xiàn)有的技術(shù)完全可以避免丟失更新,但是這樣做的代價,就是付出鎖的代價,在互聯(lián)網(wǎng)中,系統(tǒng)不單單要考慮數(shù)據(jù)的-致性,還要考慮系統(tǒng)的性能。試想,在互聯(lián)網(wǎng)中使用過多的鎖,--旦出現(xiàn)商品搶購這樣的場景,必然會導致大量的線程被掛起和恢復,因為使用了鎖之后,一個時刻只能有一個線程訪問數(shù)據(jù),這樣整個系統(tǒng)就會十分緩慢,當系統(tǒng)被數(shù)千甚至數(shù)萬用戶同時訪問時,過多的鎖就會引發(fā)宕機,大部分用戶線程被掛起,等待持有鎖事務的完成,這樣用戶體驗就會十分糟糕。因為用戶等待的時間會十分漫長,一般而言,互聯(lián)網(wǎng)系統(tǒng)響應超過5秒,就會讓用戶覺得很不友好,進而引發(fā)用戶忠誠度下降的問題。所以選擇隔離級別的時候,既需要考慮數(shù)據(jù)的一致性避免臟數(shù)據(jù),又要考慮系統(tǒng)性能的問題。因此數(shù)據(jù)庫的規(guī)范就提出了4種隔離級別來在不同的程度上壓制丟失更新。
隔離級別
未提交讀
最低的隔離級別,含義是允許一個事務讀取另外一個事務沒有提交的數(shù)據(jù)。未提交讀是一種危險的隔離級別,實際開發(fā)中應用不廣
- 優(yōu)點:并發(fā)能力高。適合那些對數(shù)據(jù)一致性沒有要求而追求高并發(fā)的場景
- 缺點:出現(xiàn)臟讀
讀寫提交
指一個事務只能讀取一個事務已經(jīng)提交的數(shù)據(jù),不能讀取未提交的數(shù)據(jù)
- 優(yōu)點:克服臟讀
- 缺點:出現(xiàn)不可重復讀
可重復讀
可重復讀的目標是克服讀寫提交中出現(xiàn)的不可重復讀的現(xiàn)象,因為在讀寫提交的時候,可能出現(xiàn)一些值的變化,影響當前事務的執(zhí)行
- 優(yōu)點:克服不可重復讀
- 缺點:出現(xiàn)幻讀
串行化
數(shù)據(jù)庫最高的隔離級別,它會要求所有的SQL都會按照順序執(zhí)行,這樣就可以克服上訴隔離級別出現(xiàn)的各種問題,所以它能完全保證數(shù)據(jù)的一致性
追求更高的隔離級別,它能更好地保證數(shù)據(jù)的一致性,但是也要付出鎖的代價。有了鎖,就意味著性能的丟失,而且隔離級別越高,性能越是直線下降。
所以在選擇隔離級別時,要考慮的不單單是數(shù)據(jù)一致性問題,還要考慮系統(tǒng)的性能問題
一般而言,選擇隔離級別會以讀寫提交為主,它能防止臟讀,而不能避免不可重復讀和幻讀,為了克服數(shù)據(jù)不一致性和性能問題,程序開發(fā)者還設(shè)計了樂觀鎖,甚至不再使用數(shù)據(jù)庫而使用其他手段
對于隔離級別,不同的數(shù)據(jù)庫支持也是不一樣的
- Oracle只支持讀寫提交和串行化,默認隔離級別為讀寫提交
- MySQL能支持4種,默認隔離級別為可重復讀
傳播行為
在Spring中,當一個方法調(diào)用另外一個方法,可以讓事務采取不同的策略工作,如新建事務或掛起當前事務
?????
在一個批量任務執(zhí)行的過程中,調(diào)用多個交易時,如果有一些交易發(fā)生異常,只是回滾出現(xiàn)異常的交易,而不是里整個批量任務,這樣就能夠是的那些沒有問題的交易可以吮吸完成,而有問題的交易則不做任何事情
@Transcation
對于聲明式事務,使用@Transaction進行標注,可標注在類活著方法上,當它標注在類上時,代表這個類所有公共(public)非靜態(tài)的方法都將啟用事務功能
默認配置下 Spring 只會回滾運行時、未檢查異常(繼承自 RuntimeException 的異常)或者 Error。
- 捕獲RuntimeException
- 捕獲Error
- 并不捕獲Checked Exception
有了@Transcation,Spring就會知道從哪啟動事務,約定流程:
當上下文開始調(diào)用被@Transcation標注的類或者方法時,Spring就會產(chǎn)生AOP的功能。請注意事務的底層需要啟動AOP功能,這就是Spring事務的底層實現(xiàn)
如有一個保存用戶的方法,加入 @Transactional 注解,使用默認配置,拋出異常之后,事務會自動回滾,數(shù)據(jù)不會插入到數(shù)據(jù)庫。
@RestController public class HouseController {@Autowiredprivate HouseRepository houseRepository;@GetMapping("/test1")public String test1(){houseRepository.save(new House("house1", "100平方米"));houseRepository.save(new House("house2", "100平方米"));houseRepository.save(new House("house3", "100平方米"));houseRepository.save(new House("house444444444", "100平方米"));houseRepository.save(new House("house5", "100平方米"));return "success";}@GetMapping("/test2")@Transactionalpublic String test2(){houseRepository.save(new House("house6", "100平方米"));houseRepository.save(new House("house7", "100平方米"));houseRepository.save(new House("house8", "100平方米"));houseRepository.save(new House("house999999999", "100平方米"));houseRepository.save(new House("house10", "100平方米"));return "success";} }test1方法沒有加入事務,test2方法加入了事務注解。
test1:當輸入http://localhost:8888/test1
數(shù)據(jù)庫中插入了三條數(shù)據(jù)
因為第四條數(shù)據(jù)太長,所以插入失敗,導致第五條正常數(shù)據(jù)插入失敗,這并不是我們想要的,要么全成功,要么全失敗
test2:輸入http://localhost:8888/test2
數(shù)據(jù)庫中數(shù)據(jù)不變依然是三條數(shù)據(jù),插入失敗,所以全部回滾
本文借鑒:《深入淺出Spring Boot 2.x》書中有更詳細的例子
返回頂部
轉(zhuǎn)載于:https://www.cnblogs.com/echola/p/10999052.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的SpringBoot声明式事务的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 梦到蟒蛇咬自己是什么意思
- 下一篇: 06 Nginx