2012-01-23 335 views
6

在Grails應用程序中,服務方法的默認行爲是它們是事務性的,並且如果拋出未經檢查的異常,事務將自動回滾。但是,在Groovy中,不會強制處理(或重新拋出)檢查的異常,因此如果服務方法拋出檢查的異常,則事務將不會回滾。考慮到這一點,似乎是可取的每個標註的Grails服務類Grails服務交易行爲

@Transactional(rollbackFor = Throwable.class) 
class MyService { 

    void writeSomething() { 
    } 
} 

假設我有MyService其他方法,其中一個只讀取數據庫,以及其他不接觸DB,有以下幾種註釋是否正確?

@Transactional(readOnly = true) 
void readSomething() {} 

// Maybe this should be propagation = Propagation.NOT_SUPPORTED instead? 
@Transactional(propagation = Propagation.SUPPORTS) 
void dontReadOrWrite() {} 

爲了回答這個問題,我想你需要知道我的意圖是:

  • 如果異常是從任何方法拋出並有正在進行的交易,它會被回滾。例如,如果writeSomething()調用dontReadOrWrite(),並且從後者拋出異常,則由前者開始的事務將被回滾。我假設rollbackFor類級別的屬性被各個方法繼承,除非它們明確地覆蓋它。
  • 如果有正在進行的任何事務,一個將不會啓動對像dontReadOrWrite
  • 方法如果沒有交易正在進行時readSomething()時,一個只讀事務將會啓動。如果正在進行讀寫事務,它將參與此事務。

回答

1

我認爲你正在尋找的是更細化的事務管理,並且使用@Transactional註釋是正確的方向。也就是說,有一個Grails Transaction Handling Plugin可以給你你正在尋找的行爲。需要注意的是,您將需要在DomainClass.withTransaction閉包中包裝服務方法調用,並將您尋找的非標準行爲作爲參數映射提供給withTransaction()方法。

作爲一個說明,在後端,這是通過使用@Transactional註釋來改變事務在運行時的行爲,正是你正在談論的。插件文檔非常好,所以我不認爲你會發現自己沒有足夠的指導。

希望這是你在找什麼。

4

您的代碼是正確的:您確實希望在您的服務類中的單個方法上使用Spring @Transactional註釋來獲得您要查找的粒度,您是對的,您希望SUPPORTS for dontReadOrWrite(NOT_SUPPORTED將暫停現有的事務,根據您所描述的內容,這些事務不會爲您購買任何東西,並且需要您的軟件花費週期,所以沒有增益會有痛苦),並且您想要默認傳播行爲(REQUIRED)用於readSomething。

但是,要記住Spring事務性行爲,一個重要的事情是Spring通過將您的類包裝在執行相應事務設置的代理中,調用您的方法並在相應事務拆除時執行事務管理控制返回。並且(關鍵地),這個事務管理代碼是只有在代理上調用方法時調用,如果writeSomething()直接調用第一個項目符號中的dontReadOrWrite(),則該方法不會發生。

如果你需要一個多數民衆贊成通過另一種方法,你有兩個選擇,我知道,如果你想使用Spring的@Transactional註解的事務管理,不斷的調用方法不同的事務行爲:

  1. 移動該方法被另一個調用到不同的服務類中,該服務類將通過Spring代理從您的原始服務類訪問。
  2. 將方法留在原來的位置。在您的服務類中聲明一個成員變量,使其與您的服務類的接口具有相同的類型,並使其成爲@Autowired,它將爲您提供對服務類的Spring代理對象的引用。然後,當你想用不同的事務行爲調用你的方法時,在該成員變量上而不是直接執行它,並且Spring事務代碼將按照你想要的方式觸發。

方法#1是巨大的,如果這兩種方法真的不反正關係,因爲它解決了你的問題,而混淆誰最終維護你的代碼,而且也沒有辦法不小心忘記調用支持事務的方法。

方法#2通常是更好的選擇,假設你的方法都在同一個服務中有一個原因,你不會真的想把它們分開。但是如果維護人員不理解Spring交易的這種皺紋,那麼你必須記得在每個你稱之爲的地方調用它,所以這是有代價的。我通常願意付出這樣的代價,不會讓我的服務班不自然地分化,但一如既往,這取決於你的情況。