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

Hibernate 事務 vs Spring 事務:核心差異與整合架構深度解析

     編輯:Java 相關知識

核心定位差異

維度Hibernate 事務Spring 事務
本質JDBC/JTA 事務的輕量封裝基於 AOP 的宣告式事務管理框架
管理層級資料存取層 (DAO 層)業務邏輯層 (Service 層)
API 風格程式化 (手動 begin/commit/rollback)宣告式 (@Transactional) + 程式化
傳播行為不支援 (需自行協調)完整支援 7 種傳播行為
隔離級別委派給底層連線統一定義 5 種隔離級別
跨資源事務不支援 (單 SessionFactory)支援 JTA、多資料源、跨資源管理器

Hibernate 事務機制深度解析

本質:JDBC/JTA 封裝器

Hibernate `Transaction` 介面實作類:

  • JDBCTransaction:封裝 `java.sql.Connection`,呼叫 `setAutoCommit(false)`、`commit()`、`rollback()`
  • JTATransaction:委派給 JTA `UserTransaction`,適用應用伺服器環境
  • CMTTransaction:容器管理事務 (EJB 環境)

配置方式 (hibernate.cfg.xml)

<property name="hibernate.transaction.factory_class">
    org.hibernate.transaction.JDBCTransactionFactory
</property>
<!-- 或 JTA 環境 -->
<property name="hibernate.transaction.factory_class">
    org.hibernate.transaction.JTATransactionFactory
</property>
<property name="hibernate.transaction.manager_lookup_class">
    org.hibernate.transaction.WeblogicTransactionManagerLookup
</property>

程式化使用範例

Session session = sessionFactory.openSession();
Transaction tx = null;
try {
    tx = session.beginTransaction();
    // 業務操作
    session.save(entity);
    session.update(entity2);
    tx.commit();
} catch (Exception e) {
    if (tx != null) tx.rollback();
    throw e;
} finally {
    session.close();
}

局限性

  1. 侵入業務代碼: 事務邊界與業務邏輯耦合
  2. 無傳播機制: 方法 A 呼叫方法 B 時,無法自動加入/掛起/新建事務
  3. 單資料源: 難以協調多個 SessionFactory 或混合 JDBC/Hibernate 操作
  4. 例外處理繁瑣: 每處需 try-catch-finally

Spring 事務管理架構

核心組件

  • PlatformTransactionManager: 事務管理器介面,核心實現:
    • `DataSourceTransactionManager`:單一 JDBC DataSource (Hibernate 3/4/5 `SessionFactory` 也適用)
    • `HibernateTransactionManager`:專用於 Hibernate `SessionFactory` (推薦)
    • `JtaTransactionManager`:分散式事務 (JTA)
  • TransactionDefinition: 事務屬性定義 (傳播、隔離、超時、唯讀)
  • TransactionStatus: 事務執行狀態 (存檔點、回滾標記、新事務標記)

宣告式事務:@Transactional 核心屬性

@Transactional(
    propagation = Propagation.REQUIRED,  // 預設:有事務加入,無則新建
    isolation = Isolation.READ_COMMITTED, // 預設:資料庫預設隔離級別
    timeout = 30,                         // 超時秒數,-1 為無限制
    readOnly = false,                     // 唯讀優化提示
    rollbackFor = {Exception.class},      // 指定回滾異常
    noRollbackFor = {BusinessException.class} // 指定不回滾異常
)
public void businessMethod() { ... }

七大傳播行為詳解

| 傳播行為 | 行為描述 | 適用場景 | |----------|----------|----------| | `REQUIRED` | 有事務加入,無則新建 | **最常用**,一般業務方法 | | `SUPPORTS` | 有事務加入,無則非事務執行 | 查詢方法、唯讀操作 | | `MANDATORY` | 必須在現有事務中執行,否則拋出異常 | 強制要求事務上下文的核心操作 | | `REQUIRES_NEW` | **掛起現有事務,新建獨立事務** | 獨立提交/回滾:日誌記錄、審計、補償操作 | | `NOT_SUPPORTED` | 掛起現有事務,以非事務方式執行 | 大量報表查詢、不需一致性的操作 | | `NEVER` | 不得在事務中執行,否則拋出異常 | 明確禁止事務的特殊場景 | | `NESTED` | 嵌套事務 (JDBC 存檔點),外層回滾內層必回滾 | 細粒度回滾控制 (較少用) |

隔離級別對照

| Spring 常數 | 對應資料庫級別 | 髒讀 | 不可重複讀 | 幻讀 | |-------------|---------------|------|------------|------| | `DEFAULT` | 資料庫預設 | 視 DB | 視 DB | 視 DB | | `READ_UNCOMMITTED` | 讀未提交 | ✓ | ✓ | ✓ | | `READ_COMMITTED` | 讀已提交 | ✗ | ✓ | ✓ | | `REPEATABLE_READ` | 可重複讀 | ✗ | ✗ | ✓ | | `SERIALIZABLE` | 串列化 | ✗ | ✗ | ✗ |

整合架構:Spring 管理 Hibernate 事務

Spring 配置 (XML)

<bean id="sessionFactory" 
      class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="packagesToScan" value="com.example.entity"/>
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
            <prop key="hibernate.show_sql">true</prop>
        </props>
    </property>
</bean>

<bean id="transactionManager" 
      class="org.springframework.orm.hibernate5.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>

<tx:annotation-driven transaction-manager="transactionManager"/>

Spring Boot 自動配置 (零配置)

# application.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/db
    username: root
    password: xxx
  jpa:
    hibernate:
      ddl-auto: update
# 只要引入 spring-boot-starter-data-jpa,自動配置:
# - DataSource
# - LocalContainerEntityManagerFactoryBean (JPA) / SessionFactory (Hibernate)
# - JpaTransactionManager / HibernateTransactionManager
# - @EnableTransactionManagement

DAO 層使用 Spring 管理的 Session

@Repository
public class UserDao {
    @Autowired private SessionFactory sessionFactory;

    protected Session getSession() {
        // 取得 Spring 事務綁定的 Session (若有事務) 或新建
        return sessionFactory.getCurrentSession();
    }

    public void save(User user) {
        getSession().save(user);  // 無需手動 begin/commit/close
    }
}

Service 層宣告式事務

@Service
@Transactional  // 類別層級預設:REQUIRED, READ_COMMITTED
public class UserService {
    @Autowired private UserDao userDao;

    public void register(User user) {
        userDao.save(user);  // 在 Spring 事務中執行
        sendWelcomeEmail(user);  // 同一事務
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void sendWelcomeEmail(User user) {
        // 獨立事務:即使註冊回滾,郵件記錄仍保留
        emailLogDao.save(new EmailLog(user.getEmail(), "WELCOME"));
    }
}

關鍵差異總結:為什麼選 Spring 事務?

  1. 關注點分離: 事務邊界從 DAO 移至 Service,DAO 專注資料存取,Service 專注業務流程
  2. 宣告式降低侵入性: 業務代碼零事務 API,透過 AOP 織入
  3. 傳播機制解決複雜業務: `REQUIRES_NEW` 實現獨立子事務,`NESTED` 實現細粒度回滾
  4. 統一異常處理: `rollbackFor` 統一定義回滾規則,避免漏寫 `rollback()`
  5. 整合生態系: 無縫整合 JPA、JDBC、MyBatis、多資料源、分散式事務
  6. 測試支援: `@Transactional` 測試方法自動回滾,保持測試資料乾淨

遷移建議:從 Hibernate 程式化事務遷移到 Spring

  1. 移除所有 DAO/Service 中的 `session.beginTransaction()`、`commit()`、`rollback()`、`close()`
  2. 配置 `HibernateTransactionManager` + `@EnableTransactionManagement`
  3. DAO 使用 `sessionFactory.getCurrentSession()` 取代 `openSession()`
  4. Service 方法加上 `@Transactional`,根據業務調整傳播/隔離/回滾規則
  5. 測試驗證:確認事務邊界正確、例外正確回滾、巢狀調用傳播行為符合預期
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved