java - enabletransactionmanagement - spring boot @transactional




@Transactional註釋屬於哪裡? (12)

你應該將@Transactional放在DAO類和/或它們的方法中,還是最好使用DAO對象來註釋正在調用的Service類? 或者是否有意義的註釋這兩個“層”?


@Transactional應該在服務層上使用,因為它包含業務邏輯。 DAO層通常只有數據庫CRUD操作。

// the service class that we want to make transactional
@Transactional
public class DefaultFooService implements FooService {

    Foo getFoo(String fooName);

    Foo getFoo(String fooName, String barName);

    void insertFoo(Foo foo);

    void updateFoo(Foo foo);
}

春季文檔: https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/transaction.htmlhttps://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/transaction.html


@Transactional Annotations應該放在所有不可分割的操作周圍。 使用@Transactional事務傳播會自動處理。在這種情況下,如果通過當前方法調用另一個方法,那麼該方法將可以選擇加入正在進行的事務。

舉個例子:

我們有2個模型即CountryCityCountryCity模型的關係映射就像一個Country可以有多個城市一樣,因此映射就像,

@OneToMany(fetch = FetchType.LAZY, mappedBy="country")
private Set<City> cities;

在這裡,國家將多個城市映射到了Lazily 。 因此,當我們從數據庫中檢索Country對象時,這裡是@Transactinal角色,然後我們將獲取Country對象的所有數據,但不會獲取Set of cities,因為我們正在取出城市LAZILY

//Without @Transactional
public Country getCountry(){
   Country country = countryRepository.getCountry();
   //After getting Country Object connection between countryRepository and database is Closed 
}

當我們想從國家對象訪問Set of Cities時,我們將在該Set中獲得空值,因為Set的對像只創建了這個Set,並沒有初始化那裡的數據來獲取Set的值,我們使用@Transactional即,

//with @Transactional
@Transactional
public Country getCountry(){
   Country country = countryRepository.getCountry();
   //below when we initialize cities using object country so that directly communicate with database and retrieve all cities from database this happens just because of @Transactinal
   Object object = country.getCities().size();   
}

所以基本上@Transactional是服務可以在單個事務中進行多次調用而不關閉與終點的連接。


或者是否有意義的註釋這兩個“層”? - 註釋服務層和dao層是否有意義 - 如果要確保DAO方法始終在DAO中傳播為“mandatory”的服務層調用(傳播)。 這將為從UI層(或多個控制器)調用DAO方法提供一些限制。 另外 - 當單元測試DAO層 - 特別是DAO註釋時,也將確保它被測試用於事務功能。


事務註釋應該放在所有不可分割的操作周圍。

例如,您的電話是“更改密碼”。 這包括兩個操作

  1. 更改密碼。
  2. 審核更改。
  3. 通過電子郵件向客戶發送密碼已更改。

所以在上面,如果審計失敗,那麼密碼更改是否也會失敗? 如果是這樣,那麼交易應該是1和2左右(所以在服務層)。 如果電子郵件失敗(可能應該有某種失敗的安全措施,以免失敗),那麼它是否應該回滾更改密碼和審核?

在決定將@Transactional放在哪裡時,這些問題是您需要問的問題。


對於數據庫級別的事務

大多數情況下,我在方法級使用了DAO中的@Transactional ,所以配置可以專門用於方法/使用默認(必需)

  1. DAO的獲取數據的方法(select ..) - 不需要@Transactional這可能會導致一些開銷,因為還需要執行事務攔截器/和AOP代理。

  2. DAO的插入/更新方法將獲得@Transactional

非常好的博客關於transctional

針對應用級別 -
我正在使用業務邏輯的事務處理,我希望能夠在出現意外錯誤時進行回滾

@Transactional(rollbackFor={MyApplicationException.class})
public void myMethod(){

    try {    
        //service logic here     
    } catch(Throwable e) {

        log.error(e)
        throw new MyApplicationException(..);
    }
}

我將@Transactional放置在@Service層上,並將rollbackFor設置為任何異常並readOnly以進一步優化事務。

默認@Transactional只會查找RuntimeException (Unchecked Exceptions),通過設置回滾到Exception.class (Checked Exceptions),它將回滾任何異常。

@Transactional(readOnly = false, rollbackFor = Exception.class)

請參閱已檢查與未經檢查的例外


我認為交易屬於服務層。 這是知道工作單位和用例的人。 如果您有多個DAO注入需要在單個事務中協同工作的服務,那麼這是正確的答案。


最好是在服務層中擁有它! 這在我昨天遇到的一篇文章中有清楚的解釋! 這裡是你可以看看的鏈接


正常的情況是在服務層級註釋,但這取決於你的要求。

在服務層註釋會導致比在DAO級別註釋更長的事務。 取決於可以解決問題的事務隔離級別,因為並發事務不會在例如對像中看到彼此的更改。 可重複閱讀。

註釋DAO將盡可能縮短事務處理時間,但缺點是您的服務層所暴露的功能不會在單個(可回滾)事務中完成。

如果傳播模式設置為默認值,則註釋兩個圖層都沒有意義。



總的來說,我同意其他人的觀點,即交易通常從服務級別開始(取決於您當然需要的粒度)。

然而,與此同時,我還開始向我的DAO層(以及其他不允許啟動事務但需要現有事務的層@Transactional(propagation = Propagation.MANDATORY)添加@Transactional(propagation = Propagation.MANDATORY) ,因為在您擁有的情況下更容易檢測錯誤忘記在主叫方開始交易(例如服務)。 如果您的DAO使用強制傳播進行註釋,則會在調用該方法時收到一個異常,指出沒有活動事務。

我也有一個集成測試,在這個集合測試中,我檢查了所有bean(bean post processor)的註解,並且如果在不屬於服務層的bean中存在一個帶有非Mandatory的傳播的@Transactional註解,則失敗。 這樣我就可以確保我們不會在錯誤的層上啟動事務。


通常,應該在服務層進行交易。

但如前所述,操作的原子性告訴我們註釋是必要的。 因此,如果你使用像Hibernate這樣的框架,對一個對象的單個“保存/更新/刪除/ ...修改”操作有可能修改幾個表中的幾行(由於通過對像圖的級聯),當然,這個特定的DAO方法也應該有事務管理。





dao