| 維度 | Hibernate 事務 | Spring 事務 |
|---|---|---|
| 本質 | JDBC/JTA 事務的輕量封裝 | 基於 AOP 的宣告式事務管理框架 |
| 管理層級 | 資料存取層 (DAO 層) | 業務邏輯層 (Service 層) |
| API 風格 | 程式化 (手動 begin/commit/rollback) | 宣告式 (@Transactional) + 程式化 |
| 傳播行為 | 不支援 (需自行協調) | 完整支援 7 種傳播行為 |
| 隔離級別 | 委派給底層連線 | 統一定義 5 種隔離級別 |
| 跨資源事務 | 不支援 (單 SessionFactory) | 支援 JTA、多資料源、跨資源管理器 |
Hibernate `Transaction` 介面實作類:
JDBCTransaction:封裝 `java.sql.Connection`,呼叫 `setAutoCommit(false)`、`commit()`、`rollback()`JTATransaction:委派給 JTA `UserTransaction`,適用應用伺服器環境CMTTransaction:容器管理事務 (EJB 環境)<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();
}
@Transactional(
propagation = Propagation.REQUIRED, // 預設:有事務加入,無則新建
isolation = Isolation.READ_COMMITTED, // 預設:資料庫預設隔離級別
timeout = 30, // 超時秒數,-1 為無限制
readOnly = false, // 唯讀優化提示
rollbackFor = {Exception.class}, // 指定回滾異常
noRollbackFor = {BusinessException.class} // 指定不回滾異常
)
public void businessMethod() { ... }
<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"/>
# 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
@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
@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"));
}
}