JDBC 3.0 引入 Savepoint 介面,允許在事務中設定邏輯回滾點,發生錯誤時可選擇回滾至特定保存點而非整個事務,極大提升了資料庫操作的靈活性。本文詳細講解 Savepoint 核心 API、使用流程與完整代碼範例。
| 方法 | 說明 |
|---|---|
Connection.setSavepoint(String name) | 建立命名保存點,回傳 Savepoint 物件 |
Connection.releaseSavepoint(Savepoint sp) | 釋放指定保存點 |
Connection.rollback(Savepoint sp) | 回滾至指定保存點 |
try (Connection conn = DriverManager.getConnection(url, user, pass)) {
conn.setAutoCommit(false); // 開啟事務
Savepoint sp1 = conn.setSavepoint("SP_BEFORE_INSERT");
stmt.executeUpdate("INSERT INTO Employees VALUES (106, 20, 'Rita', 'Tez')");
// 故意執行錯誤 SQL
stmt.executeUpdate("INSERTED INTO Employees VALUES (107, 22, 'Sita', 'Tez')"); // 語法錯
conn.commit(); // 若無錯誤提交
} catch (SQLException e) {
conn.rollback(sp1); // 回滾至保存點,第一條 INSERT 也會被撤銷
}
import java.sql.*;
public class JDBCSavepointDemo {
static final String URL = "jdbc:mysql://localhost:3306/EMP";
static final String USER = "root";
static final String PASS = "password";
public static void main(String[] args) {
try (Connection conn = DriverManager.getConnection(URL, USER, PASS)) {
conn.setAutoCommit(false);
try (Statement stmt = conn.createStatement()) {
// 1. 查詢初始資料
printRs(stmt.executeQuery("SELECT id, first, last, age FROM Employees"));
// 2. 刪除 ID=110 前設保存點
Savepoint sp1 = conn.setSavepoint("DEL_110");
stmt.executeUpdate("DELETE FROM Employees WHERE ID = 110");
System.out.println("已刪除 ID=110");
// 3. 發現刪錯,回滾至 sp1
conn.rollback(sp1);
System.out.println("已回滾至 DEL_110 保存點");
// 4. 正確刪除 ID=95 前設另一保存點
Savepoint sp2 = conn.setSavepoint("DEL_95");
stmt.executeUpdate("DELETE FROM Employees WHERE ID = 95");
// 5. 最終結果
printRs(stmt.executeQuery("SELECT id, first, last, age FROM Employees"));
conn.commit();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
static void printRs(ResultSet rs) throws SQLException {
rs.beforeFirst();
while (rs.next()) {
System.out.printf("ID: %d, Age: %d, First: %s, Last: %s%n",
rs.getInt("id"), rs.getInt("age"), rs.getString("first"), rs.getString("last"));
}
System.out.println("---");
}
}
初始資料:
ID: 95, Age: 20, First: Sima, Last: Chug
ID: 100, Age: 18, First: Zara, Last: Ali
...
ID: 110, Age: 20, First: Sima, Last: Chug
已刪除 ID=110
已回滾至 DEL_110 保存點 <-- ID=110 恢復
最終資料 (ID=95 被刪除):
ID: 100, Age: 18, First: Zara, Last: Ali
...
ID: 110, Age: 20, First: Sima, Last: Chug <-- ID=110 仍在
ID: 95 已不存在
conn.setAutoCommit(false),否則每條 SQL 即時提交,保存點無效。releaseSavepoint() 可釋放資源,避免記憶體洩漏。Savepoint 讓複雜業務邏輯(如多步驟訂單處理、批次匯入驗證)能精細控制事務邊界,配合 rollback(Savepoint) 可大幅減少重試成本,是 JDBC 進階開發必備技能。