首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> DB2 資料庫 >> DB2 教學

JDBC 事務管理實戰:自動提交、保存點與轉賬案例全解析

     編輯:DB2 教學

JDBC 事務管理實戰:自動提交、保存點與轉賬案例全解析

JDBC 事務通過 Connection 控制,核心三方法:setAutoCommit、commit、rollback。本文詳解事務邊界控制、保存點部分回滾、經典轉賬案例及最佳實踐模板。

1. 核心 API

方法作用關鍵點
setAutoCommit(false)開啟事務默認 true,每條 SQL 獨立事務
commit()提交事務所有操作持久化
rollback()回滾事務撤銷所有未提交操作

2. 標準事務代碼模板

Connection con = null;
try {
    con = dataSource.getConnection();
    con.setAutoCommit(false);  // 開啟事務

    // 業務操作...
    stmt1.executeUpdate(sql1);
    stmt2.executeUpdate(sql2);

    con.commit();  // 提交
} catch (Exception e) {
    if (con != null) try { con.rollback(); } catch (SQLException ignored) {}
    throw new RuntimeException(e);
} finally {
    close(con, stmt, rs);
}

3. 經典案例:支付寶轉賬

張三轉 1000 給李四,需兩條 SQL 原子執行:

public void transfer(boolean fail) {
    Connection con = null;
    PreparedStatement pstmt = null;
    try {
        con = JdbcUtils.getConnection();
        con.setAutoCommit(false);

        String sql = "UPDATE account SET balance = balance + ? WHERE id = ?";
        pstmt = con.prepareStatement(sql);

        // 張三 -1000
        pstmt.setDouble(1, -1000);
        pstmt.setInt(2, 1);
        pstmt.executeUpdate();

        if (fail) throw new RuntimeException("模擬網絡中斷");

        // 李四 +1000
        pstmt.setDouble(1, 1000);
        pstmt.setInt(2, 2);
        pstmt.executeUpdate();

        con.commit();
    } catch (Exception e) {
        if (con != null) try { con.rollback(); } catch (SQLException ignored) {}
        throw new RuntimeException(e);
    } finally {
        JdbcUtils.close(con, pstmt);
    }
}

4. 保存點:部分回滾

JDBC 3.0 引入,需數據庫支持。con.getMetaData().supportsSavepoints() 驗證。

// 設置保存點
Savepoint sp = con.setSavepoint();

// 操作 3、4...
// 若條件不滿足,回滾到保存點(事務未結束)
if (balance < 0) {
    con.rollback(sp);  // 僅撤銷 sp 後的操作
    System.out.println("回滾到保存點,事務繼續");
}
// 最後提交整個事務
con.commit();

關鍵:rollback(sp) 不結束事務,僅撤銷保存點後的操作;必須最終調用 commit() 或 rollback() 結束事務。

5. 保存點實戰:有條件的雙向轉賬

@Test
public void conditionalTransfer() {
    Connection con = null;
    PreparedStatement pstmt = null;
    try {
        con = JdbcUtils.getConnection();
        con.setAutoCommit(false);
        String sql = "UPDATE account SET balance = balance + ? WHERE name = ?";
        pstmt = con.prepareStatement(sql);

        // 張三 -1W
        pstmt.setDouble(1, -10000); pstmt.setString(2, "zs"); pstmt.executeUpdate();
        // 李四 +1W
        pstmt.setDouble(1, 10000); pstmt.setString(2, "ls"); pstmt.executeUpdate();

        Savepoint sp = con.setSavepoint();  // 保存點 A

        // 李四 -100W(承諾返還)
        pstmt.setDouble(1, -1000000); pstmt.setString(2, "ls"); pstmt.executeUpdate();
        // 張三 +100W
        pstmt.setDouble(1, 1000000); pstmt.setString(2, "zs"); pstmt.executeUpdate();

        // 檢查李四餘額
        pstmt = con.prepareStatement("SELECT balance FROM account WHERE name = ?");
        pstmt.setString(1, "ls");
        ResultSet rs = pstmt.executeQuery();
        rs.next();
        double balance = rs.getDouble(1);

        if (balance < 0) {
            con.rollback(sp);  // 回滾到保存點 A,李四不扣款,張三不收款
            System.out.println("張三,你上當了!");
        }
        con.commit();  // 提交前兩步轉賬
    } catch (Exception e) {
        if (con != null) try { con.rollback(); } catch (SQLException ignored) {}
        throw new RuntimeException(e);
    } finally {
        JdbcUtils.close(con, pstmt);
    }
}

6. 最佳實踐總結

  1. 業務邏輯方法層級開啟/提交/回滾事務,避免跨層傳遞 Connection。
  2. 使用連接池,確保同一事務複用同一物理連接。
  3. 異常捕獲後務必回滾,防止髒數據殘留。
  4. 長事務拆分為短事務,或使用保存點細粒度控制。
  5. 分布式事務場景引入 JTA/XA 或柔性事務 (TCC/Saga)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved