1. 程式人生 > 實用技巧 >淺談@Async和@Transaction

淺談@Async和@Transaction

@Async註解使用條件:

1、@Async註解一般用在類的方法上,如果用在類上,那麼這個類所有的方法都是非同步執行的;

2、所使用的@Async註解方法的類物件應該是Spring容器管理的bean物件;

3、呼叫非同步方法類上需要配置上註解@EnableAsync。

使用注意:

1、預設情況下(即@EnableAsync註解的mode=AdviceMode.PROXY),同一個類內部沒有使用@Async註解修飾的方法呼叫@Async註解修飾的方法,是不會非同步執行的,這點跟 @Transitional 註解類似,底層都是通過動態代理實現的(詳見:Java中的引用和動態代理的實現詳解)。如果想實現類內部自呼叫也可以非同步,則需要切換@EnableAsync註解的mode=AdviceMode.ASPECTJ;

2、任意引數型別都是支援的,但是方法返回值必須是void或者Future型別。當使用Future時,你可以使用 實現了Future介面的ListenableFuture介面或者CompletableFuture類與非同步任務做更好的互動。如果非同步方法有返回值,沒有使用Future<V>型別的話,呼叫方獲取不到返回值。

迴圈依賴問題解決:

A的某個field或者setter依賴了B的例項物件,同時B的某個field或者setter依賴了A的例項物件,Spring通過三級快取解決迴圈依賴。同樣對於迴圈依賴的場景,構造器注入和prototype型別的屬性注入都會初始化Bean失敗,因為@Service預設是單例的,所以單例的屬性注入是可以成功的。

總結:

1、構造器注入和prototype型別的field注入發生迴圈依賴時都無法初始化;

2、field注入單例的bean時,儘管有迴圈依賴,但bean仍然可以被成功初始化。詳見:Spring-bean的迴圈依賴以及解決方式

但是如果A類裡面方法使用了 @Async 註解,就引起了迴圈依賴報錯,這是為什麼呢。查閱官方文件:Async註解初始化

NOTE: AsyncConfigurer configuration classes get initialized early in the application context bootstrap. If you need any dependencies on other beans there, make sure to declare them 'lazy' as far as possible in order to let them go through other post-processors as well.

在Spring 啟動過程中Async註解為類建立代理類,這樣Spring 三級快取中就沒有單例bean的早期引用物件而是Async代理物件,快取裡面找不到bean原始早期物件就引起報錯。

解決方法是為注入的其他類增加懶載入@Lazy註解,解決迴圈依賴報錯問題。

懶載入@Lazy:

預設情況下 Bean 等同於 @Lazy(false),在 IOC 容器啟動的時候就建立了。如果定義 Bean 的時候加上 @Lazy ,則在 IOC 容器載入的時候,該 Bean 不會被初始化,在呼叫該 Bean 的時候才會被初始化。

插播sql注入問題:

sql中經常用like進行模糊查詢,而模糊查詢就要用到百分號“%”,下劃線“_”這些萬用字元,其中“%”匹配任意多個字元,“_”匹配單個字元。如果我們想要模糊查詢帶有萬用字元的字串,如“60%”,“user_name”,就需要對萬用字元進行轉義,有兩種方式,如下:

1、反斜槓是轉義符,通過反斜槓來轉義%,使其不再是萬用字元。這裡第一個%是萬用字元,第二個%不是萬用字元。

select percent from score where percent like '%0\%';

2、這種是通過escape關鍵字進行轉義,將特定符號後的字元進行轉義,這裡斜槓後面的%就不再是萬用字元,斜槓之前的%仍然起萬用字元作用。

select percent from score where percent like '%0/%' escape '/';

建議concat配合escape使用。