From Gossip@Openhome

Java Gossip: 交易(Transaction)

交易是一組原子(Atomic)操作(一組SQL執行)的工作單元,這個工作單元中的所有原子操作在進行期間,與其它交易隔離,免於數據來源的交相更新而 發生混亂,交易中的所有原子操作,要嘛全部執行成功,要嘛全部失敗(即使只有一個失敗,所有的原子操作也要全部撤消)。

舉個簡單的例子,一個客戶從A銀行轉帳至B銀行,要作的動作為從A銀行的帳戶扣款、在B銀行的帳戶加上轉帳的金額,兩個動作必須成功,如果有一個動作失敗,則此次轉帳失敗。

在JDBC中,可以操作Connection的setAutoCommit()方法,給定它false引數,在下達一連串的SQL語句後,自行呼叫Connection的commit()來送出變更,如果中間發生錯誤,則呼叫rollback()來撤消所有的執行,例如:

  • TransactionDemo.java
package onlyfun.caterpillar;

import java.sql.*;

public class TransactionDemo {
private static String driver = "com.mysql.jdbc.Driver";
private static String url = "jdbc:mysql://localhost:3306/demo";
private static String user = "root";
private static String password = "123456";

private static void loadDriver() {
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}

public static void main(String[] args) {
loadDriver();

Connection conn = null;
Statement stmt = null;

try {
conn = DriverManager.getConnection(
url, user, password);

conn.setAutoCommit(false);

stmt = conn.createStatement();

stmt.execute("...."); // SQL
stmt.execute("....");
stmt.execute("....");

conn.commit();

}
catch(SQLException e) {
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}
finally {
if(stmt != null) {
try {
stmt.close();
}
catch(SQLException e) {
e.printStackTrace();
}
}
if(conn != null) {
try {
conn.close();
}
catch(SQLException e) {
e.printStackTrace();
}
}
}
}
}

如果您在交易管理時,僅想要rollback回某個SQL執行點,則您可以設定save point,例如:
conn.setAutoCommit(false);

Statement stmt = conn.createStatement();
stmt.executeUpdate("....");
stmt.executeUpdate("....");

Savepoint savepoint = conn.setSavepoint(); // 設定save point
stmt.executeUpdate("....");

// 如果因故rollback
conn.rollback(savepoint);
. . .
conn.commit();
// 記得釋放save point
conn.releaseSavepoint(
savepoint);

Statement 批次處理 中介紹過批次執行SQL,批次處理前設定auto commit為 false,如果中間有個SQL執行錯誤,則應該rollback整個批次處理。