spring事務里面開啟線程插入報錯了是否會回滾
1.前言
一道非常有意思的面試題目。大概是這樣子的,如果在一個事務中,開啟線程進行插入更新等操作,如果報錯了,事務是否會進行回滾。
2.代碼
示例1
@RequestMapping("/test/publish/submit") public String testPublish1() { log.info("start..."); transactionTemplate.execute(new TransactionCallback<String>() { @Override public String doInTransaction(TransactionStatus status) { TElement element = new TElement(); element.setfElementId(10L); element.setfElementName("111"); mapper.insertSelective(element); element = new TElement(); element.setfElementId(10L); element.setfElementName("222"); mapper.insertSelective(element); return "OK"; } }); log.info("end..."); return "ok"; }
示例2
@RequestMapping("/test/publish/submit2") public String testPublish2() { log.info("start..."); transactionTemplate.execute(new TransactionCallback<String>() { @Override public String doInTransaction(TransactionStatus status) { es.submit(() -> { TElement element = new TElement(); element.setfElementId(10L); element.setfElementName("111"); mapper.insertSelective(element); }); es.submit(() -> { TElement element = new TElement(); element.setfElementId(10L); element.setfElementName("222"); mapper.insertSelective(element); }); return "OK"; } }); log.info("end..."); return "ok"; }
3.結論
示例1
element.setfElementId(10L); 為主鍵。SQL在第一次插入id=10的時候是沒有問題的,在第二次插入id=10的時候,由于主鍵沖突了,導致報錯,然后整個事務都會進行回滾,這是沒有問題的。是spring的事務幫助我們來進行回滾等操作的。我們可以看到如下代碼,他是對整個result = action.doInTransaction(status);進行了try catch。如果拋異常,就會回滾
@Override @Nullable public <T> T execute(TransactionCallback<T> action) throws TransactionException { Assert.state(this.transactionManager != null, "No PlatformTransactionManager set"); if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) { return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action); } else { TransactionStatus status = this.transactionManager.getTransaction(this); T result; try { result = action.doInTransaction(status); } catch (RuntimeException | Error ex) { // Transactional code threw application exception -> rollback rollbackOnException(status, ex); throw ex; } catch (Throwable ex) { // Transactional code threw unexpected exception -> rollback rollbackOnException(status, ex); throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception"); } this.transactionManager.commit(status); return result; } }
示例2
示例2首先是transactionTemplate.execute是一個主main線程。然后在第一個子線程插入了一個數(shù)據(jù),第二個子線程也插入了一個數(shù)據(jù)。那么現(xiàn)在就是有三個線程,一個是main線程,一個是A線程,一個是B線程。
main線程正常執(zhí)行不報錯,A線程正常插入不報錯,B線程由于主鍵沖突報錯。
我們可以通過上面action.doInTransaction(status);看出來,他對這塊代碼進行了try catch。也就是主線程進行了try catch。那么也就是只要主線程沒有報錯,這個事務就不會被捕獲,也就不會回滾了。無論你A,B還是CDEFG子線程出問題了,只要不影響main線程,那事務就不會回滾呢?
因此我們可以得出一個結論,在示例2中,A線程會插入成功,B線程插入失敗,事務不會回滾,最終插入成功。這個其實與我們平常的想法所違背了。
因此如果想要主線程拋出異常,得讓主線程感知到子線程異常了,主動地去throw異常。比如我們可以設置一個flag,子線程報錯了 flag=true。主線程檢測到flag為true,就主動拋出一個exception
4.最后
這道面試題非常有意思,起初以為會回滾,沒想到不會回滾。查看代碼得知,原來是catch住的是主線程,并不是子線程。同樣注解式事務類似。因此如果想要事務生效,盡量避免在事務中使用多線程來進行插入更新等操作
到此這篇關于spring事務里面開啟線程插入,報錯了是否會回滾?的文章就介紹到這了,更多相關spring事務開啟線程插入內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
解決SpringBoot中使用@Transactional注解遇到的問題
這篇文章主要介紹了SpringBoot中使用@Transactional注解遇到的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09Springboot 在普通類型注入Service或mapper
這篇文章主要介紹了Springboot 在普通類型注入Service或mapper,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11解決java轉義json出現(xiàn)\u0000 等亂碼的問題
這篇文章主要介紹了解決java轉義json出現(xiàn)\u0000 等亂碼的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-03-03