成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

線上問題事跡(一)數據庫事務居然都沒生效?

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

[[352574]]

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

  • 但僅為方法添加@Transactional注解

你就以為這就夠了嗎?

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

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

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

案例

用戶表實體類

 

DAO 層 

根據username查詢所有數據

  1. @Repository 
  2. public interface UserRepository extends JpaRepository<UserEntity, Long> { 
  3.     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方法再次嘗試:

  1. public int createUserWrong2(String name) { 
  2.     try { 
  3.         this.createUserPublic(new UserEntity(name)); 
  4.     } catch (Exception ex) { 
  5.         log.error("create user failed because {}", ex.getMessage()); 
  6.     } 
  7.     return userRepository.findByName(name).size(); 
  8.  
  9. //標記了@Transactional的public方法 
  10. @Transactional 
  11. public void createUserPublic(UserEntity entity) { 
  12.     userRepository.save(entity); 
  13.     if (entity.getName().contains("test")) 
  14.         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方法。

  1. @GetMapping("right2"
  2. public int right2(@RequestParam("name") String name) { 
  3.     try { 
  4.         userService.createUserPublic(new UserEntity(name)); 
  5.     } catch (Exception ex) { 
  6.         log.error("create user failed because {}", ex.getMessage()); 
  7.     } 
  8.     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生效:

  1. // 在UserService中通過this調用public的createUserPublic 
  2. [23:04:30.748] [http-nio-45678-exec-5] [DEBUG] [o.s.orm.jpa.JpaTransactionManager:370 ] -  
  3. Creating new transaction with name [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]:  
  4. PROPAGATION_REQUIRED,ISOLATION_DEFAULT 
  5.  
  6. [DEBUG] [o.s.orm.jpa.JpaTransactionManager       :370 ] - Creating new transaction with name [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT 
  7. //在Controller中通過注入的UserService Bean調用createUserPublic 
  8. [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中直接調用該方法。

這既能從外部(Controller中)調用UserService方法,方法又是public的能夠被動態代理AOP增強。要不你試試?看看效果如何,下回分解~

 

責任編輯:姜華 來源: JavaEdge
相關推薦

2020-11-18 08:32:07

數據庫

2020-11-18 10:16:52

數據庫回滾事務

2019-04-15 13:15:12

數據庫MySQL死鎖

2024-06-21 09:37:57

2009-09-24 14:12:22

Hibernate數據

2010-10-08 09:38:55

Android數據庫事

2025-04-08 06:00:00

2017-08-22 17:10:45

數據庫MySQL事務模型

2024-05-28 00:00:30

Golang數據庫

2021-10-03 15:00:44

數據庫mysql單機

2020-06-17 16:56:36

數據庫MySQL跨行事務

2019-05-13 08:24:58

數據庫MySQLInnoDB

2018-07-20 11:10:21

數據庫事務隔離性

2009-08-06 18:10:06

C#數據庫事務

2011-08-12 13:33:31

Oracle數據庫自治事務

2023-10-11 08:09:53

事務隔離級別

2020-08-20 07:37:21

數據庫開源框架

2022-08-01 20:29:48

分布式架構數據

2018-09-06 14:53:39

數據庫事務隔離隔離級別

2010-05-31 15:12:44

MySQL數據庫
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久精品手机视频 | 久草中文在线 | av网址在线 | 久久电影一区 | 欧美美女被c| 一本大道久久a久久精二百 国产成人免费在线 | 国产精品日韩欧美一区二区 | 欧美福利三区 | 欧美网站一区二区 | 免费观看日韩av | 日日爱夜夜操 | 国产精品欧美一区喷水 | 国产一区二区三区网站 | 亚洲国产黄 | 中文字幕在线二区 | 国产馆| 亚洲精品小视频在线观看 | 美女在线一区二区 | 日韩一级欧美一级 | 久久免费精品视频 | 日韩欧美国产一区二区 | 久久免费高清视频 | 美女久久久久久久 | 国产精品久久久久久久久久久久久 | 天堂久久天堂综合色 | 伊人影院在线观看 | 性做久久久久久免费观看欧美 | 久久区二区 | 午夜黄色| 欧美日韩在线一区 | 毛片一级片| 午夜国产一级片 | 成年网站在线观看 | 日韩a视频 | 国产一区二区精品在线观看 | 国产精品久久av | 天堂在线免费视频 | 91久久爽久久爽爽久久片 | 久久久久久免费观看 | 国产精品亚洲成在人线 | 国内av在线 |