事務(Transaction)是通路并可能更新資料庫中各種資料項的一個程式執行單元(unit)。事務通常由進階資料庫操縱語言或程式設計語言
(如SQL,C++或Java)書寫的使用者程式的執行所引起,并用形如begin transaction和end transaction語句(或函數調用)來界定。
事務由事務開始(begin transaction)和事務結束(end transaction)之間執行的全體操作組成。
例如:在關系資料庫中,一個事務可以是一條SQL語句,一組SQL語句或整個程式。
我對事務的了解最深的還是原子性;即,要麼全部操作成功,要麼都失敗。
在資料庫操作中,有時候一個功能的實作要涉及到多個表的操作,我們就以此為一個事務,必須保證多個表的變化都執行,
那麼該怎麼處理呢?
在這裡以java、mysql資料庫為例,銀行轉賬問題(事務)
事務描述:使用者a給使用者b彙款x,資料庫表中會有兩個操作,a使用者的賬目數減少x,b使用者賬目數增加x。
隻有當b使用者收到錢時,兩個操作才回執行,否則都不執行,兩人賬戶不變。
模拟操作:
public class BankExample {
private static String conStr = "jdbc:mysql://localhost/test";
private String root = "root";
private String pwd = "123";
static{
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public Connection getCon(){
try {
return DriverManager.getConnection(conStr, root, pwd);
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
BankExample be = new BankExample();
Connection con = null;
Savepoint sp = null;
int x = 0;
try {
con = be.getCon();
con.setAutoCommit(false);//設定自動遞交關閉
//操作一 a使用者減去x
String sql = "insert into a_bank values(null,?)";
PreparedStatement pstmt = con.prepareStatement(sql);
pstmt.setInt(1, 1000 - x);
pstmt.executeUpdate();
//操作二 b使用者 加上 x
String sql1 = "insert into b_bank values(null,?)";
PreparedStatement pstmt1 = con.prepareStatement(sql1);
pstmt1.setInt(1, 1000 + x);
pstmt1.executeUpdate();
sp = con.setSavepoint();//設定斷點
//列印憑條
PreparedStatement ps = con.prepareStatement("seltct * from result id=?");
ps.setString(1, "33");
ResultSet rs = ps.executeQuery();
System.out.println(rs.getString("name"));
} catch (SQLException e) {
try {
con.rollback(sp);//滾回斷點
} catch (SQLException e1) {
e1.printStackTrace();
}
}
try {
con.commit();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
保證一個事務的原子性的方法就是統一送出setAutoCommit(false),此方法隻有當調用commit()方法之後才會送出,
進而保證事務的原子性。
我在上面加了一個列印憑條的例子,以便了解SavePoint,不管有沒有憑條轉賬都可以完成,是以轉賬和列印憑條是兩個事務,
我在列印憑條的操作之前設定一個儲存點SavePoint,如果沒有憑條了會抛出SQLException異常,我在此處理儲存點讓進度”滾回到“
設定的地方然後執行就可以了!