Java @Transactional與synchronized使用的問(wèn)題
引言
@Transactional是spring通過(guò)aop讓我們輕松實(shí)現(xiàn)事務(wù)控制的一個(gè)注解;而synchronized是實(shí)現(xiàn)同步的java關(guān)鍵字;但是它們兩個(gè)不能一起使用,一起使用會(huì)出現(xiàn)
synchronized失效的問(wèn)題,這里簡(jiǎn)單記錄一下這個(gè)問(wèn)題;
發(fā)現(xiàn)問(wèn)題
我在impl中實(shí)現(xiàn)一個(gè)功能邏輯時(shí),為了保證冪等性,在方法中使用synchronized保證同一個(gè)用戶短時(shí)間內(nèi)多次請(qǐng)求只能串行執(zhí)行,因?yàn)閿?shù)據(jù)變動(dòng)涉及多張表,所以我又加了一個(gè)@Transactional注解,偽代碼如下:
@Transactional public void demo() { ...一些操作... synchronized(lock) { ...數(shù)據(jù)庫(kù)讀寫(xiě)操作... } }
然后測(cè)試時(shí)就發(fā)現(xiàn)synchronized沒(méi)有生效,確認(rèn)代碼邏輯沒(méi)有問(wèn)題后,查詢了資料發(fā)現(xiàn)了問(wèn)題;
問(wèn)題原因
這里不過(guò)多解釋@Transactional注解底層,感興趣可以自行查閱資料;
主要原因就是@Transactional注解通過(guò)aop實(shí)現(xiàn)事務(wù)管理,當(dāng)標(biāo)注該注解的方法執(zhí)行完成后才提交事務(wù),而synchronized代碼塊又是在一個(gè)事務(wù)內(nèi),就會(huì)出現(xiàn)第一個(gè)線程釋放鎖后但是事務(wù)還沒(méi)提交,第二個(gè)線程就進(jìn)入同步代碼塊獲取到未提交的數(shù)據(jù)庫(kù)數(shù)據(jù);
大致如圖:
解決問(wèn)題
大致思路
解決方法很簡(jiǎn)單,既然問(wèn)題出在事務(wù)未提交,那么只要把對(duì)應(yīng)事務(wù)操作的代碼單獨(dú)抽取出來(lái),封裝成一個(gè)單獨(dú)的方法,在synchronized中調(diào)用該方法即可;
如圖:
偽代碼為:
public void demo() { ...一些操作... synchronized(lock) { databaseOption(); // 調(diào)用數(shù)據(jù)庫(kù)操作方法 } } @Transactional public void databaseOption() { ...數(shù)據(jù)庫(kù)讀寫(xiě)操作... }
注意:@Transactional注解修飾的方法需要是public權(quán)限;
雖然這樣寫(xiě)好像解決了事務(wù)未提交的問(wèn)題,但是這樣寫(xiě)會(huì)存在新的問(wèn)題;上面這種是這兩種方法都寫(xiě)在serviceImpl中,但是這樣調(diào)用databaseOption方法就會(huì)出現(xiàn)@Transactional事務(wù)不生效的情況;
@Transactional事務(wù)不生效問(wèn)題
所以在同一個(gè)類內(nèi)部調(diào)用@Transactional標(biāo)注的方法事務(wù)也不會(huì)開(kāi)啟,原因是:
@Transactional事務(wù)管理是基于動(dòng)態(tài)代理對(duì)象的代理邏輯實(shí)現(xiàn)的,那么如果在類內(nèi)部調(diào)用類內(nèi)部的事務(wù)方法,這個(gè)調(diào)用事務(wù)方法的過(guò)程并不是通過(guò)代理對(duì)象來(lái)調(diào)用的,而是直接通過(guò)this對(duì)象來(lái)調(diào)用方法,繞過(guò)的代理對(duì)象,肯定就是沒(méi)有代理邏輯了
依然是@Transactional的底層原理,可以好好研究一下這個(gè)注解,面試就有的聊了;
那么解決方法就是:
不要把由@Transactional修飾的databaseOption方法和調(diào)用它的方法放到同一個(gè)類中;這里你可以多寫(xiě)個(gè)service放databaseOption方法,但是這樣好像沒(méi)有什么意義;我選擇的是把同步代碼塊放到controller中,在controller中調(diào)用serviceImpl中的databaseOption方法;
偽代碼:
controller類
@RestController public class TestController { @Resource private TestService testService; @PostMapping("/test") public String testInterface() { ...一些操作... synchronized(lock) { testService.databaseOption(); // 調(diào)用數(shù)據(jù)庫(kù)操作方法 } } }
service類
@Service("testService") public class TestServiceImpl implements TestService { @Transactional public void databaseOption() { ...數(shù)據(jù)庫(kù)讀寫(xiě)操作... } }
這樣就能保證@Transactional事務(wù)生效;但是這樣寫(xiě)的缺點(diǎn)就是一些邏輯會(huì)被拆分到controller中,可讀性會(huì)稍差點(diǎn);
總結(jié)
這就是這兩天我踩的坑,總的來(lái)說(shuō)所有問(wèn)題的出現(xiàn)都是由于對(duì)@Transactional這個(gè)注解理解的不透徹,以后還是要了解該注解的實(shí)現(xiàn)原理;
到此這篇關(guān)于Java @Transactional與synchronized使用的問(wèn)題的文章就介紹到這了,更多相關(guān)Java @Transactional與synchronized內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java同步鎖Synchronized底層源碼和原理剖析(推薦)
- java同步鎖的正確使用方法(必看篇)
- 95%的Java程序員人都用不好Synchronized詳解
- Java?synchronized同步關(guān)鍵字工作原理
- Java synchronized偏向鎖的概念與使用
- Java?synchronized輕量級(jí)鎖實(shí)現(xiàn)過(guò)程淺析
- Java synchronized重量級(jí)鎖實(shí)現(xiàn)過(guò)程淺析
- Java?synchronized與死鎖深入探究
- Java synchronized與CAS使用方式詳解
- 淺析Java關(guān)鍵詞synchronized的使用
- synchronized及JUC顯式locks?使用原理解析
- java鎖synchronized面試常問(wèn)總結(jié)
- Java?HashTable與Collections.synchronizedMap源碼深入解析
- Java?Synchronized鎖的使用詳解
- AQS加鎖機(jī)制Synchronized相似點(diǎn)詳解
- Java必會(huì)的Synchronized底層原理剖析
- 一個(gè)例子帶你看懂Java中synchronized關(guān)鍵字到底怎么用
- 詳解Java?Synchronized的實(shí)現(xiàn)原理
- Synchronized?和?ReentrantLock?的實(shí)現(xiàn)原理及區(qū)別
- Java同步鎖synchronized用法的最全總結(jié)
相關(guān)文章
解決mybatis使用char類型字段查詢oracle數(shù)據(jù)庫(kù)時(shí)結(jié)果返回null問(wèn)題
這篇文章主要介紹了mybatis使用char類型字段查詢oracle數(shù)據(jù)庫(kù)時(shí)結(jié)果返回null問(wèn)題的解決方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-06-06Spring中bean的初始化和銷毀幾種實(shí)現(xiàn)方式詳解
這篇文章主要介紹了Spring中bean的初始化和銷毀幾種實(shí)現(xiàn)方式詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11SpringBoot集成I18n國(guó)際化文件在jar包外生效問(wèn)題
這篇文章主要介紹了SpringBoot集成I18n國(guó)際化文件在jar包外生效問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04UniApp?+?SpringBoot?實(shí)現(xiàn)微信支付和退款功能
這篇文章主要介紹了UniApp?+?SpringBoot?實(shí)現(xiàn)微信支付和退款功能,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06Spring Boot集成SpringFox 3.0與Pageable參數(shù)處理方法
這篇文章主要介紹了Spring Boot集成SpringFox 3.0與Pageable參數(shù)處理,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-10-10scala當(dāng)中的文件操作和網(wǎng)絡(luò)請(qǐng)求的實(shí)現(xiàn)方法
這篇文章主要介紹了scala當(dāng)中的文件操作和網(wǎng)絡(luò)請(qǐng)求的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06Springboot項(xiàng)目中kaptcha驗(yàn)證碼的使用方式
這篇文章主要介紹了Springboot項(xiàng)目中kaptcha驗(yàn)證碼的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05springboot?+mybatis?使用PageHelper實(shí)現(xiàn)分頁(yè)并帶條件模糊查詢功能
這篇文章主要介紹了springboot?+mybatis?使用PageHelper實(shí)現(xiàn)分頁(yè)并帶條件模糊查詢功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-02-02