久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

怎么解決數據庫事務居然沒生效問題

150次閱讀
沒有評論

共計 3488 個字符,預計需要花費 9 分鐘才能閱讀完成。

本篇內容介紹了“怎么解決數據庫事務居然沒生效問題”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓丸趣 TV 小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

Spring 聲明式事務提供給 Javaer 們方便的事務配置方式,再搭配 Spring  Boot 自動配置,基本只需在方法上添加 @Transactional 注解,即可瞬間開啟方法的事務性配置。

但僅為方法添加 @Transactional 注解

你就以為這就夠了嗎?

事務未被正確處理,一般不會導致停止服務,更不易在測試階段復現。但隨系統業務越來越復雜,就會帶來大量數據不一致問題,隨后就是大量線上問題而后人工排查檢修數據。

1 你的 Spring 事務怎么才算生效?

使用 @Transactional 開啟聲明式事務時,靈魂發問:事務生效了嗎?

案例

用戶表實體類

 

DAO 層

根據 username 查詢所有數據

@Repository public interface UserRepository extends JpaRepository UserEntity, Long  { List UserEntity  findByName(String name); }

Service 層

UserService 類

負責業務邏輯處理,包括如下方法:

createUserWrong1 調用 private 方法:

createUserPrivate,被 @Transactional 注解。當傳入的用戶名包含 test 則拋異常,讓用戶的創建操作失敗,期望事務回滾:

getUserCount

 

Controller 層

調用一下剛才定義的 UserService 中的入口方法 createUserWrong1。

測試結果

即便用戶名不合法,用戶也能創建成功。刷新瀏覽器,多次發現非法用戶注冊。

2 @Transactional 怎么確保生效?

除非特殊配置 (比如使用 AspectJ 靜態織入實現 AOP),否則只有定義在 public 方法上的 @Transactional 才能生效。

Spring 默認通過動態代理實現 AOP,對目標方法增強,private 方法無法代理到,自然也無法動態增強事務處理邏輯。

那簡單,把 createUserPrivate 方法改為 public 即可。

在 UserService 中再建一個入口方法 createUserWrong2,來調用這個 public 方法再次嘗試:

public int createUserWrong2(String name) { try { this.createUserPublic(new UserEntity(name)); } catch (Exception ex) { log.error( create user failed because {} , ex.getMessage()); } return userRepository.findByName(name).size(); } // 標記了 @Transactional 的 public 方法  @Transactional public void createUserPublic(UserEntity entity) { userRepository.save(entity); if (entity.getName().contains(test)) throw new RuntimeException(invalid username!  }

新的 createUserWrong2 方法事務同樣不生效。

必須通過代理過的類從外部調用目標方法

要調用增強過的方法必然是調用代理后的對象。

嘗試修改 UserService,注入一個 self,然后再通過 self 實例調用標記有 @Transactional 注解的 createUserPublic 方法。設置斷點可以看到,self 是由 Spring 通過 CGLIB 方式增強過的類。

CGLIB 通過繼承方式實現代理類,private 方法在子類不可見,自然也就無法進行事務增強;

this 指針代表對象自己,Spring 不可能注入 this,所以通過 this 訪問方法必然不是代理。

把 this 改為 self,在 Controller 中調用 createUserRight 方法可以驗證事務生效了:非法的用戶注冊操作可以回滾。

雖然在 UserService 內部注入自己調用自己的 createUserPublic 可以正確實現事務,但這不符合習慣用法。更合理的實現方式是,讓 Controller 直接調用之前定義的 UserService 的 createUserPublic 方法。

@GetMapping(right2) public int right2(@RequestParam( name) String name) { try { userService.createUserPublic(new UserEntity(name)); } catch (Exception ex) { log.error( create user failed because {} , ex.getMessage()); } return userService.getUserCount(name); }

this 自調用 /self 調用 /Controller 調用 UserService

this 自調用

        無法走到 Spring 代理類

后兩種

        調用的 Spring 注入的 UserService,通過代理調用才有機會對 createUserPublic 方法進行動態增強。

推薦在開發時打開相關 Debug 日志,以了解 Spring 事務實現的細節。

比如 JPA 數據庫訪問,可以這么開啟 Debug 日志:

logging.level.org.springframework.orm.jpa=DEBUG

開啟日志后再比較下在 UserService 中 this 調用、Controller 中通過注入的 UserService  Bean 調用 createUserPublic 的區別。

很明顯,this 調用因沒走代理,事務沒有在 createUserPublic 生效,只在 Repository 的 save 生效:

//  在 UserService 中通過 this 調用 public 的 createUserPublic [23:04:30.748] [http-nio-45678-exec-5] [DEBUG] [o.s.orm.jpa.JpaTransactionManager:370 ] - Creating new transaction with name [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT [DEBUG] [o.s.orm.jpa.JpaTransactionManager :370 ] - Creating new transaction with name [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT // 在 Controller 中通過注入的 UserService Bean 調用 createUserPublic [10:10:47.750] [http-nio-45678-exec-6] [DEBUG] [o.s.orm.jpa.JpaTransactionManager :370 ] - Creating new transaction with name [org.geekbang.time.commonmistakes.transaction.demo1.UserService.createUserPublic]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT

這種實現在 Controller 里處理異常顯得繁瑣,還不如直接把 createUserWrong2 加 @Transactional 注解,然后在 Controller 中直接調用該方法。

“怎么解決數據庫事務居然沒生效問題”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注丸趣 TV 網站,丸趣 TV 小編將為大家輸出更多高質量的實用文章!

正文完
 
丸趣
版權聲明:本站原創文章,由 丸趣 2023-07-27發表,共計3488字。
轉載說明:除特殊說明外本站除技術相關以外文章皆由網絡搜集發布,轉載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 长武县| 廊坊市| 林西县| 石台县| 鞍山市| 东平县| 穆棱市| 浑源县| 夏津县| 五家渠市| 固阳县| 图们市| 北京市| 定西市| 苗栗县| 南川市| 长白| 游戏| 三门县| 西贡区| 无锡市| 临西县| 孟津县| 陆河县| 中超| 治县。| 寻甸| 林西县| 万全县| 乌兰察布市| 隆回县| 宣恩县| 昌吉市| 洛隆县| 漠河县| 武城县| 中牟县| 瓮安县| 兴城市| 江孜县| 嘉鱼县|