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

Java 事務管理總結:JDBC 本地事務、JTA 分布式事務、Spring 事務抽象與選型實戰指南

     編輯:Java 綜合教學

Java 事務管理總結:JDBC 本地事務、JTA 分布式事務、Spring 事務抽象與選型實戰指南

事務是企業級應用數據一致性的基石。本文系統總結 JDBC 本地事務、JTA/XA 分布式事務、容器事務(CMT)、Spring 事務抽象 四大體系的原理、API、隔離級別、傳播行為、優缺點對比與選型決策樹,並附贈 JDBC 事務核心代碼模板、Spring 声明式事務最佳實踐,作為架構師與開發者的桌面參考手冊。

一、事務核心屬性(ACID)速記

  • A - 原子性:單位不可分,全成全敗。
  • C - 一致性:約束前後不變,數據完整。
  • I - 隔離性:併發互不干擾,靠鎖/MVCC 實現。
  • D - 持久性:提交即永久,掉電不丟,靠 WAL/Redo Log。

二、三大 Java 事務體系對比總覽

維度 JDBC 本地事務 JTA 分布式事務 容器事務 (CMT/EJB)
核心 APIConnection.setAutoCommit/commit/rollbackUserTransaction、TransactionManager、XAResource@TransactionAttribute / ejb-jar.xml
事務範圍單個 Connection / 單數據庫多 XAResource / 多數據庫/消息隊列EJB 方法級,容器管理
實現複雜度低,手動控制高,需 XA 驅動、TM、2PC 協議中,聲明式配置,但綁定 EJB 容器
性能開銷最小(單階段提交)大(2PC、鎖持有久、網絡交互)中等(容器攔截開銷)
適用場景單庫應用、簡單業務跨庫轉賬、訂單-庫存強一致傳統 Java EE 單體、EJB 架構
現代地位基石,Spring 管理底層核心,Spring JtaTransactionManager 封裝已淘汰,EJB 幾乎不再使用

三、JDBC 本地事務深度實戰

1. 核心代碼模板(生產級)


Connection conn = null;
PreparedStatement ps = null;
try {
    conn = dataSource.getConnection();
    conn.setAutoCommit(false); // 關鍵:開啟手動事務
    
    ps = conn.prepareStatement("UPDATE account SET balance=balance-? WHERE id=?");
    ps.setInt(1, 500); ps.setString(2, "A");
    ps.executeUpdate();
    
    ps = conn.prepareStatement("UPDATE account SET balance=balance+? WHERE id=?");
    ps.setInt(1, 500); ps.setString(2, "B");
    ps.executeUpdate();
    
    conn.commit(); // 統一提交
} catch (Exception e) {
    if (conn != null) try { conn.rollback(); } catch (SQLException ignore) {}
    throw new RuntimeException("轉賬失敗", e); // 統一異常轉換
} finally {
    closeQuietly(ps);
    closeQuietly(conn); // 歸還連接池
}

2. 事務隔離級別與併發異常

隔離級別 常量 髒讀 不可重複讀 幻讀 實現機制
READ_UNCOMMITTED1✅✅✅無鎖,極少用
READ_COMMITTED2❌✅✅行鎖(寫),Oracle/PostgreSQL 默認
REPEATABLE_READ4❌❌✅行鎖+間隙鎖,MySQL InnoDB 默認
SERIALIZABLE8❌❌❌表鎖/範圍鎖,性能最差
  • 髒讀:讀到未提交數據。
  • 不可重複讀:同一查詢前後結果不一致(數據被修改)。
  • 幻讀:同一條件前後查詢行數變化(數據被插入/刪除)。
  • JDBC 設置:conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED)。

3. Savepoint 保存點:細粒度回滾


Savepoint sp1 = conn.setSavepoint("SP1");
stmt.executeUpdate("INSERT ...");
Savepoint sp2 = conn.setSavepoint("SP2");
stmt.executeUpdate("UPDATE ...");
conn.rollback(sp2); // 回滾到 SP2,SP1 保留的 INSERT 生效
conn.commit();

四、JTA/XA 分布式事務核心機制

1. XA 兩階段提交 (2PC) 流程

  1. 準備階段:TM 發 prepare() → 各 RM 執行本地事務、寫 redo/undo log、持有鎖、返回 XA_OK。
  2. 提交階段:全 OK → TM 發 commit() → RM 正式提交、釋放鎖;任一失敗 → TM 發 rollback() → 全部回滾。

2. 關鍵接口

  • XADataSource → getXAConnection() → XAConnection → getXAResource() → XAResource(prepare/commit/rollback)。
  • 普通 DataSource 無 getXAResource,不能參與 JTA。

3. 獨立 JTA 實現選型

產品 特點 Spring Boot 整合
Atomikos成熟、文檔豐富、支持 Spring Boot Starterspring-boot-starter-jta-atomikos
Bitronix輕量、嵌入式友好手動配置 BitronixTransactionManager
NarayanaWildFly 內置、功能最全、支持 LRA/WS-ATnarayana-spring-boot-starter

五、Spring 事務抽象:統一編程模型

1. 核心接口三劍客

  • PlatformTransactionManager:事務管理入口,getTransaction(Definition)、commit/status、rollback/status。
  • TransactionDefinition:隔離級別、傳播行為、超時、只讀等屬性定義。
  • TransactionStatus:運行時狀態,isNewTransaction()、setRollbackOnly()、isRollbackOnly()。

2. 實現類選擇

  • DataSourceTransactionManager:單 DataSource 本地事務(最常用)。
  • JtaTransactionManager:委托 JTA 實現(Atomikos/Narayana/容器 TM),支持分布式事務。
  • HibernateTransactionManager:Hibernate Session 事務(已少用)。

3. 七大傳播行為詳解

傳播常量 行為描述 典型場景
REQUIRED支持當前事務,無則新建(默認)90% 業務方法
SUPPORTS支持當前事務,無則非事務執行只讀查詢、非關鍵輔助操作
MANDATORY必須在事務中運行,無則拋異常強制要求事務上下文的核心業務
REQUIRES_NEW掛起當前事務,新建獨立事務日志記錄、審計、獨立提交的子業務
NOT_SUPPORTED掛起當前事務,非事務運行長耗時非事務操作、外部 API 調用
NEVER非事務運行,有事務則拋異常嚴禁事務的場景
NESTED嵌套事務(Savepoint),外層回滾內層跟隨,內層回滾外層可選細粒度回滾控制,JDBC 3.0+ 支持

4. 聲明式事務最佳實踐(@Transactional)


@Service
@Transactional(rollbackFor = Exception.class) // 類級默認:所有受檢/非受檢異常回滾
public class AccountService {

    @Autowired AccountMapper mapper;

    // 方法級覆蓋:只讀優化、特定傳播、超時
    @Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
    public Account getAccount(String id) { return mapper.selectById(id); }

    @Transactional(propagation = Propagation.REQUIRES_NEW, timeout = 30)
    public void logTransfer(TransferLog log) { logMapper.insert(log); }

    // 核心業務:默認 REQUIRED,異常回滾
    public void transfer(String from, String to, int amount) {
        mapper.decreaseBalance(from, amount);
        // 業務檢查拋出業務異常 → 觸發回滾
        if (mapper.getBalance(from) < 0) throw new InsufficientBalanceException();
        mapper.increaseBalance(to, amount);
    }
}

5. 事務失效十大坑

  1. 方法非 public(代理攔截不到)。
  2. 類內部自調用(this.method() 繞過代理)。
  3. 捕獲異常未重拋(catch { log } 吞掉異常)。
  4. 拋出非 rollbackFor 指定異常(默認只回滾 RuntimeException/Error)。
  5. 數據源未配置事務管理器 / 多數據源未指定 @Transactional("txManager")。
  6. 使用 @Transactional 在非 Spring Bean 上(普通類、final 類、final 方法)。
  7. 異步線程中調用(事務上下文不傳遞)。
  8. 引擎不支持事務(MyISAM、MongoDB 無事務)。
  9. 嵌套事務未正確配置 NESTED / 數據庫不支持 Savepoint。
  10. 序列化隔離級別導致死鎖/超時。

六、選型決策樹:架構師視角


業務場景分析
   │
   ├─ 單數據庫、單應用
   │     └─ → Spring @Transactional + DataSourceTransactionManager (首選)
   │
   ├─ 多數據庫 / 數據庫+MQ / 微服務強一致
   │     ├─ 業務容許最終一致?
   │     │     ├─ 是 → TCC / Saga / 本地消息表 / 事務消息 (RocketMQ) → 避開分布式事務
   │     │     └─ 否 → 必須強一致
   │     │           ├─ 同一應用跨庫 → Spring JtaTransactionManager + Atomikos/Narayana + XADataSource
   │     │           └─ 微服務跨服務 → Seata AT 模式 / XA 模式 / TCC 模式
   │
   └─ 歷史 EJB 應用維護
         → 容器 CMT(了解即可,新項目禁用)

七、總結

Java 事務技術棧經歷了 JDBC 手動 → JTA/XA 標準 → 容器 CMT → Spring 統一抽象 → 微服務柔性事務 的演進。核心認知三點:

  1. 本地事務是基石:單庫場景 Spring @Transactional 管理 DataSourceTransactionManager 最簡潔高效。
  2. 分布式事務是雙刃劍:XA/2PC 提供強一致但犧牲性能/可用性,**能不用盡量不用**,優先選最終一致性方案(Seata、TCC、Saga)。
  3. Spring 抽象屏蔽差異:同一套 @Transactional 注解,切換 PlatformTransactionManager 實現即可在本地/分布式間遷移,業務代碼零侵入。

掌握 隔離級別、傳播行為、失效坑點、選型邏輯,你就擁有了在任何 Java 架構下設計正確事務邊界的核心能力。

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