首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Spring 宣告式事務:DAO 層 vs Service 層配置詳解

     編輯:Java 相關知識

核心概念

Spring 透過 AOP 實現宣告式事務,核心是 TransactionProxyFactoryBean(舊版)或 <tx:advice>(新版)。事務邊界的位置直接影響資料一致性與效能,常見兩種策略:事務在 DAO 層與事務在 Service 層。

方案一:事務置於 DAO 層

適用於「單一 DAO 操作即為一個事務單元」的簡單場景。

<!-- 交易管理器 -->
<bean id="transactionManager"
  class="org.springframework.orm.hibernate3.HibernateTransactionManager">
  <property name="sessionFactory" ref="sessionFactory"/>
</bean>

<!-- DAO 目標物件 -->
<bean id="companyDAOTarget"
  class="com.vstsoft.querycompany.dao.impl.CompanyDAOImpl">
  <property name="sessionFactory" ref="sessionFactory"/>
</bean>

<!-- DAO 事務代理 -->
<bean id="companyDAOProxy"
  class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
  <property name="transactionManager" ref="transactionManager"/>
  <property name="target" ref="companyDAOTarget"/>
  <property name="transactionAttributes">
    <props>
      <prop key="insert*">PROPAGATION_REQUIRED</prop>
      <prop key="delete*">PROPAGATION_REQUIRED</prop>
      <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
    </props>
  </property>
</bean>

<!-- Service 注入 DAO 代理 -->
<bean name="companyManageTarget"
  class="com.vstsoft.querycompany.service.impl.CompanyManageTarget">
  <property name="companyDAO" ref="companyDAOProxy"/>
</bean>

特點:每個 DAO 方法獨立開啟/提交事務;Service 呼叫多個 DAO 方法時,無法保證跨方法的原子性。

方案二:事務置於 Service 層(推薦)

符合「一個業務用例=一個事務」的領域驅動設計原則。

<!-- JTA 交易管理器(跨資源) -->
<bean id="jtaTransactionManager"
  class="org.springframework.transaction.jta.JtaTransactionManager"/>

<!-- DAO 僅需普通代理(無事務屬性) -->
<bean id="companyDAOProxy"
  class="org.springframework.aop.framework.ProxyFactoryBean">
  <property name="proxyInterfaces"
    value="com.vstsoft.querycompany.dao.CompanyDAO"/>
  <property name="target" ref="companyDAOTarget"/>
</bean>

<!-- Service 事務代理 -->
<bean id="companyManageProxy"
  class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
  <property name="transactionManager" ref="jtaTransactionManager"/>
  <property name="target" ref="companyManageTarget"/>
  <property name="transactionAttributes">
    <props>
      <prop key="set*">PROPAGATION_REQUIRED</prop>
      <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
    </props>
  </property>
</bean>

關鍵差異:
1. DAO 不再有事務屬性,僅作為資料存取介面。
2. Service 方法(如 setData())包含「查詢→刪除→插入」多步驟,若任一步驟拋出 RuntimeException,整個事務回滾;全部成功才提交。
3. 若需跨多個資料源,必須使用 JtaTransactionManager。

傳播行為速查表

傳播屬性行為
PROPAGATION_REQUIRED有事務則加入,無則建立新事務(預設)
PROPAGATION_REQUIRES_NEW總是建立新事務,掛起現有事務
PROPAGATION_NESTED巢狀事務,外層回滾則內層回滾,內層回滾不影響外層
readOnly標記唯讀,資料庫可優化鎖策略

最佳實踐建議

  1. 預設將事務邊界放在 Service 層,確保業務邏輯原子性。
  2. 唯讀查詢方法加上 readOnly 提升效能。
  3. 跨服務、跨資料源操作才啟用 JTA。
  4. 新專案改用 @Transactional 註解 + <tx:annotation-driven>,配置更簡潔。

結語

事務層級的選擇直接關係資料一致性。理解「DAO 層事務=細粒度、Service 層事務=業務粒度」是架構設計的關鍵決策點。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved