1. 程式人生 > >Spring事務註解@Transactional的坑爹陷阱

Spring事務註解@Transactional的坑爹陷阱

生產系統核心部分特別是涉及到賬戶的批量處理,放在凌晨定時執行,結果出問題了,現象很詭異:

1)問題偶發,但沒有規律

2)程式沒有按照預定步驟處理資料庫相關資料

3)發生後也沒有發現有死鎖,但出現異常的鎖

前後折騰了三次,但一直沒有找到根源。

後來另外一個問題發生時,分析發現數據庫事務處理形同虛設,用Spring @Transactional註解的資料庫事務完全沒有生效,讓人費解,甚至懷疑所用的PostgreSQL資料庫是不是有問題,在事務控制方面是不是有Bug。

後來查詢資料,發現是對Spring @Transactional事務註解理解不當,使用有誤造成的。坑爹的陷阱,讓團隊加了好幾次班 敲打

由於Spring是通過AOP方式實現@Transactional事務註解的,由於AOP的侷限性,在一些特定的情況下,@Transactional註解不會生效,直接導致資料庫的併發控制出現問題。

以下是一篇關於Spring @Transactional註解失效的一篇文章,文章還提供了一個工具類,用來除錯判斷當前事務是否開啟。

文章的要點如下:

  1. 1)  @Transactional annotations only work on public methods. If you have a private or protected method with this annotation there’s no (easy) way for Spring AOP to see the annotation. It doesn’t go crazy trying to find them so make sure all of your annotated methods are public.

  2. 2) Transaction boundaries are only created when properly annotated (see above) methods are called through a Spring proxy. This means that you need to call your annotated method directly through an @Autowired bean or the transaction will never start. If you call a method on an @Autowired bean that isn’t annotated which itself calls a public method that is annotated

    YOUR ANNOTATION IS IGNORED. This is because Spring AOP is only checking annotations when it first enters the @Autowired code.

  3. 3) Never blindly trust that your @Transactional annotations are actually creating transaction boundaries. When in doubt test whether a transaction really is active (see below)

另有一篇中文文章也闡述了類似問題和觀點

1. 在需要事務管理的地方加@Transactional 註解。@Transactional 註解可以被應用於介面定義和介面方法、類定義和類的 public 方法上

2. @Transactional 註解只能應用到 public 可見度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 註解,它也不會報錯, 但是這個被註解的方法將不會展示已配置的事務設定。

3. 注意僅僅 @Transactional 註解的出現不足於開啟事務行為,它僅僅 是一種元資料。必須在配置檔案中使用配置元素,才真正開啟了事務行為。

4. 通過 元素的 "proxy-target-class" 屬性值來控制是基於介面的還是基於類的代理被創建。如果 "proxy-target-class" 屬值被設定為 "true",那麼基於類的代理將起作用(這時需要CGLIB庫cglib.jar在CLASSPATH中)。如果 "proxy-target-class" 屬值被設定為 "false" 或者這個屬性被省略,那麼標準的JDK基於介面的代理將起作用。