国产成人精品久久免费动漫-国产成人精品天堂-国产成人精品区在线观看-国产成人精品日本-a级毛片无码免费真人-a级毛片毛片免费观看久潮喷

您的位置:首頁技術(shù)文章
文章詳情頁

Spring事務(wù)相關(guān)問題解決方案

瀏覽:74日期:2023-09-19 14:30:48

有些spring相關(guān)的知識(shí)點(diǎn)之前一直沒有仔細(xì)研究:比如spring的事務(wù),并不是沒有使用,也曾經(jīng)簡(jiǎn)單的在某些需要事務(wù)處理的方法上通過增加事務(wù)注解來實(shí)現(xiàn)事務(wù)功能,僅僅是跟隨使用(甚至并未測(cè)試過事務(wù)的正確性),至于如何在項(xiàng)目中配置事務(wù),如何才能將事務(wù)寫正確,事務(wù)的其它的一些原理性的東西從未花時(shí)間研究。最近同事正好拋出了一個(gè)問題,借此機(jī)會(huì)學(xué)習(xí)了一遍。

問題一:增加了readOnly=true的事務(wù)中包含寫操作,為什么線上運(yùn)行這段代碼是正常的呢?

@Transactional(readOnly = true) public Integer getUID(String key, String type) { keyGeneratorDao.insert(key, type); keyGeneratorDao.update(key, type); return keyGeneratorDao.select(key, type); }

我為什么對(duì)這個(gè)問題感興趣?

不懂這個(gè)readOnly參數(shù)的含義,之前寫@Transactional的注解,那都是使用的默認(rèn)值,不帶顯示參數(shù)。提出配置了readOnly參數(shù)后,理論上應(yīng)該程序報(bào)錯(cuò)而實(shí)際上沒有報(bào)錯(cuò),想搞清楚為什么。

開始寫單元測(cè)試:

在單元測(cè)試類中寫事務(wù)函數(shù)以及測(cè)試方法

@Autowired private IkeyGeneratorDao keyGeneratorDao; @Transactional(readOnly=true) public Integer getId(String key, String type){ return keyGeneratorDao.select(key, type); } @Transactional public Integer getUID(String key, String type) { keyGeneratorDao.insert(key, type); keyGeneratorDao.update(key, type); return this.getId(key,type); } @Test public void testCreateGuid(){ int guid=this.getUID('12345', 'jim'); System.out.println(guid); }

測(cè)試結(jié)果顯示正常,與上面提到的不允許進(jìn)行寫操作的觀點(diǎn)相反,于是想起典型的事務(wù)生效問題。

挖的第一個(gè)坑:如果事務(wù)采用的是cglib動(dòng)態(tài)代理,調(diào)用的方法與事務(wù)方法處在同一個(gè)類中事務(wù)不生效。

將兩個(gè)事務(wù)事務(wù)轉(zhuǎn)移到單獨(dú)的類中,然后測(cè)試,類代碼省略,只是將上面兩個(gè)標(biāo)記了@Transactional的方法封裝在一個(gè)單獨(dú)的類中。

@Autowired private KeyGeneratorService keyService; @Test public void testCreateGuid2(){ int guid=this.keyService.getUID('12345', 'jim'); System.out.println(guid); }

測(cè)試結(jié)果顯示也是正常,于是想確認(rèn)下事務(wù)到底是否生效,加入異常以測(cè)試數(shù)據(jù)是否回滾,修改代碼如下:

@Transactional public Integer getUID3(String key, String type) { keyGeneratorDao.insert(key, type); Integer.parseInt('aaa');//throw exception keyGeneratorDao.update(key, type);}

測(cè)試結(jié)果顯示事務(wù)回滾正常,可以排除事務(wù)環(huán)境配置問題。

挖的第二個(gè)坑:做測(cè)試一定要與原問題代碼盡量保持一致,否則會(huì)產(chǎn)生其它的不明原因影響判斷。通過對(duì)比原問題的代碼發(fā)現(xiàn)我寫的測(cè)試代碼與問題代碼有區(qū)別,readOnly是加在包含有寫操作的方法上,而我的是兩個(gè)方法,只有在讀的方法上增加了readOnly,于時(shí)再次修改代碼:

@Transactional(readOnly = true) public Integer getUID4(String key, String type) { keyGeneratorDao.insert(key, type); keyGeneratorDao.update(key, type); return keyGeneratorDao.select(key, type); }

測(cè)試結(jié)果顯示運(yùn)行不正常,提示如下錯(cuò)誤:Cause: java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed,到這的確說明在在加了readOnly=true的事務(wù)內(nèi)是不允許寫入操作的。為什么這段代碼在線上運(yùn)行是成功的呢,于時(shí)查看前端的調(diào)用,發(fā)現(xiàn)前端調(diào)用的并不是直接標(biāo)識(shí)了Transactional的方法,而是根據(jù)不同的具體業(yè)務(wù)重新包裝的方法,比如我們需要生成訂單的編號(hào),前端只調(diào)用genOrderCode而不調(diào)用getUID。

非事務(wù)方法在內(nèi)部調(diào)用了本類事務(wù)方法,然后非事務(wù)方法被外部調(diào)用ServicegenOrderCode,是一個(gè)非事務(wù)方法,內(nèi)部調(diào)用了getUIDgetUID,是一個(gè)事務(wù)方法

@Autowired private IkeyGeneratorDao keyGeneratorDao; @Transactional(readOnly = true) public Integer getUID(String key, String type) { keyGeneratorDao.insert(key, type); keyGeneratorDao.update(key, type); return keyGeneratorDao.select(key, type); } public String genOrderCode(Date orderDate) { SimpleDateFormat df = new SimpleDateFormat('yyMMddHH'); String ticketDate = df.format(orderDate); Integer uid = getUID(ticketDate, ORDER_CODE);return ticketDate + genRandom2(uid.toString(), 3, 3) ; }

Test,外部類調(diào)用非事務(wù)方法

@Test public void testCreateGuid3(){ String guid=this.keyService.genOrderCode(new Date()); System.out.println(guid); }

測(cè)試結(jié)果居然是正常的,這與線上運(yùn)行的結(jié)果相同,后面經(jīng)同事提醒,這又是一個(gè)不正確使用事務(wù)的案例。

挖的第三個(gè)坑:當(dāng)調(diào)用一個(gè)類的非事務(wù)方法且這個(gè)非事務(wù)方法內(nèi)部調(diào)用了本類自身的事務(wù)方法,那么事務(wù)也不會(huì)生效。

問題二:下面的代碼可以實(shí)現(xiàn)事務(wù)回滾嗎?

Service

genOrderCode方法調(diào)用 getUID2兩個(gè)方法都是具備相同的事務(wù)參數(shù) getUID2拋出異常 genOrderCode捕獲這個(gè)異常

@Transactional public Integer getUID2(String key, String type) { keyGeneratorDao.insert(key, type); Integer.parseInt('aaa');//throw exception keyGeneratorDao.update(key, type); return keyGeneratorDao.select(key, type); } @Transactional public String genOrderCode(Date orderDate) { try{ SimpleDateFormat df = new SimpleDateFormat('yyMMddHH'); String ticketDate = df.format(orderDate); Integer uid = getUID2(ticketDate, ORDER_CODE); return ticketDate + genRandom2(uid.toString(), 3, 3) ; }catch(Exception ex){ System.out.println(ex); } return null; }

Test

@Test public void testCreateGuid3(){ String guid=this.keyService.genOrderCode(new Date()); System.out.println(guid); }

執(zhí)行測(cè)試代碼,發(fā)現(xiàn)可以成功提交,但數(shù)據(jù)是不完整的,因?yàn)楦虏僮鳑]有完成。為什么會(huì)是這樣的呢?因?yàn)槟J(rèn)的Propagation.REQUIRED指明多個(gè)操作處于一個(gè)事務(wù)中,由于genOrderCode有異常處理,所以即使getUID2中發(fā)生異常,系統(tǒng)也會(huì)認(rèn)定提交是合法的,因此會(huì)出現(xiàn)插入操作正常更新不正常但事務(wù)正常提交并不回滾的情況。如果顯示指定Propagation.REQUIRES_NEW呢?

@Transactional(propagation=Propagation.REQUIRES_NEW) public Integer getUID2(String key, String type) { keyGeneratorDao.insert(key, type); Integer.parseInt('aaa');//throw exception keyGeneratorDao.update(key, type); return keyGeneratorDao.select(key, type); }

再執(zhí)行相同的測(cè)試,數(shù)據(jù)正常回滾,這里提供兩張圖,可以看的清楚些(因?yàn)槌S玫木瓦@兩種,其它的有興趣可以多多研究)

REQUIRED

Spring事務(wù)相關(guān)問題解決方案

REQUIRES_NEW

Spring事務(wù)相關(guān)問題解決方案

通過事務(wù)的兩個(gè)小問題,總結(jié)出解決問題的一些小技巧或者叫經(jīng)驗(yàn):發(fā)現(xiàn)問題之后,不要局限于某個(gè)點(diǎn),最好根據(jù)上下文來結(jié)合分析,比如問題一的readonly可寫入,單看那段代碼很難找出合理的解釋,只有結(jié)合前后端調(diào)用才能找出根本原因。寫單元測(cè)試盡量寫相同的代碼,否則有可能會(huì)出現(xiàn)一些干擾項(xiàng)影響判斷。學(xué)習(xí)呢,有時(shí)間盡量學(xué)的全點(diǎn),比如@Transactional這個(gè)注解,除了readOnly還有Propagation等等。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持好吧啦網(wǎng)。

標(biāo)簽: Spring
相關(guān)文章:
主站蜘蛛池模板: 一本三道a无线码一区v小说 | 成人亚洲网站 | 国产视频网站在线观看 | 一级一级一片免费 | 精品无码三级在线观看视频 | 韩国美女爽快一毛片免费 | 久久99热精品免费观看k影院 | 欧美日韩一区二区高清视 | 亚洲成av人片在线观看 | 九九成人 | 亚洲国产精品一区二区久 | 国产精品久久久久999 | 国产一国产一有一级毛片 | 久久国内精品自在自线软件 | 日韩欧美中文字幕一区二区三区 | 在线观看免费av网站 | 精品国产欧美一区二区五十路 | 在线观看日韩 | 3d动漫精品成人一区二区三 | 兔费看全黄三级 | 日本三级网站在线线观看 | 久久久久女人精品毛片九一 | 三a大片| 久久一二 | 玖玖爱zh综合伊人久久 | 国产综合精品一区二区 | 欧美大片国产在线永久播放 | 91精品日本久久久久久牛牛 | 国产日韩欧美在线一二三四 | 日本a级三级三级三级久久 日本a级特黄三级三级三级 | 另类专区欧美 | 欧美日韩看看2015永久免费 | 日本不卡一区在线 | 91精品国产一区二区三区四区 | 精品国产精品国产 | 中文字幕最新中文字幕中文字幕 | 成人欧美午夜视频毛片 | 精品国产一区二区二三区在线观看 | 成年女人毛片免费视频永久vip | 国产精品久久久久久福利漫画 | 久久精品免费在线观看 |