日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

使用@Transactional应注意的问题

發布時間:2025/7/14 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用@Transactional应注意的问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

使用@Transactional應注意的問題

@Transactional 基本原理概述

在應用系統調用聲明@Transactional 的目標方法時,Spring Framework 默認使用 AOP 代理,在代碼運行時生成一個代理對象,根據@Transactional 的屬性配置信息,這個代理對象決定該聲明@Transactional 的目標方法是否由攔截器 TransactionInterceptor 來使用攔截,在 TransactionInterceptor 攔截時,會在在目標方法開始執行之前創建并加入事務,并執行目標方法的邏輯, 最后根據執行情況是否出現異常,利用抽象事務管理器AbstractPlatformTransactionManager 操作數據源 DataSource 提交或回滾事務。

你需要注意的事

  • @Transactional 只能被應用到public方法上, 對于其它非public的方法,如果標記了@Transactional也不會報錯,但方法沒有事務功能
  • Spring團隊的建議是你在具體的類(或類的方法)上使用 @Transactional 注解,而不要使用在類所要實現的任何接口上。
  • 當然可以在接口上使用 @Transactional 注解,但是這將只能當你設置了基于接口的代理時它才生效。因為注解是不能繼承的,這就意味著如果你正在使用基于類的代理時,那么事務的設置將不能被基于類的代理所識別,而且對象也將不會被事務代理所包裝(將被確認為嚴重的)。因此,還是在具體的類上使用 @Transactional 注解比較好。
  • 避免 Spring 的 AOP 的自調用問題:自調用就是方法A內調用本類的另一個加上事務注解的方法B時,方法B中對數據庫的操作是不帶事務的。
  • Spring AOP 代理下,只有目標方法由外部調用,目標方法才由 Spring 生成的代理對象來管理,這會造成自調用問題。若同一類中的其他沒有@Transactional 注解的方法內部調用有@Transactional 注解的方法,有@Transactional 注解的方法的事務被忽略,不會發生回滾。

    失效原因

    方法one方法two都是public的:

    • classA中 ,任意要調用classB的方法,是通過spring代理的方式,那么spring的注解才會生效
    • classA中,方法one 調用同class內的方法two,即this調用,spring注解不會生效(例如@Cachable,@Transaction)

    解決方法

    既然已知原因,那么解決的方法就有了,核心思想就是如何獲得動態代理對象,而不是使用this去調用。

    方案一:使用AspectJ代理

    @Service public class OrderService {private void insert() {insertOrder();} @Transactionalpublic void insertOrder() {//insert log info//insertOrder//updateAccount} }

    insertOrder 盡管有@Transactional 注解,但它被內部方法 insert 調用,事務被忽略,出現異常事務不會發生回滾。

    上面的兩個問題@Transactional 注解只應用到 public 方法和自調用問題,是由于使用 Spring AOP 代理造成的。為解決這兩個問題,可以使用 AspectJ取代 Spring AOP 代理,但現在有更好的解決方法。

    方案二:利用AopContext.currentProxy()方法獲得代理

    方法的意思是嘗試返回當前AOP代理。這種做法非常簡潔,但是在默認情況下是不起作用的!因為AopContext中拿不到currentProxy,會報空指針。需要一些額外的配置,但不能對所有的注解攔截都有效,這是因為這些注解不是用的AspectJ代理,如果是@Transactional事務注解的話, 則是生效的,具體細節要翻源碼了,這里不推薦使用。

    方案三:通過ApplicationContext來獲得動態代理對象(推薦)

    @Component public class AsyncService implements ApplicationContextAware {private ApplicationContext applicationContext;public void async1() {System.out.println("1:" + Thread.currentThread().getName());// 使用AppicationContext來獲得動態代理的bean,然后再執行你調用的方法this.applicationContext.getBean(AsyncService.class).async2();}@Asyncpublic void async2() {System.out.println("2:" + Thread.currentThread().getName());}// 注入ApplicationContext@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;} }

    轉載于:https://www.cnblogs.com/keeya/p/11180612.html

    總結

    以上是生活随笔為你收集整理的使用@Transactional应注意的问题的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。