在JDBC事務操作中,都是通過Connection完成的。
同一個事務中所有的操作,都在使用同一個Connection對象。
Connection中與事務相關的三個方法: setAutoCommit(boolean):設置是否為自動提交事務,如果true(默認值就是true)表示自動提交,也就是每條執行的SQL語句都是一個單獨的事務,如果設置false,那麼就相當於開啟了事務了;con.setAutoCommit(false)表示開啟事務!commit():提交結束事務;con.commit();表示提交事務rollback():回滾結束事務。con.rollback();表示回滾事務
jdbc處理事務的代碼格式:
try {
con.setAutoCommit(false);//開啟事務…
….
…
con.commit();//try的最後提交事務
} catch() {
con.rollback();//回滾事務
}
比如支付寶轉賬!張三轉1000塊到李四的賬戶,這其實需要兩條SQL語句:
給張三的賬戶減去1000元;給李四的賬戶加上1000元。 如果在第一條SQL語句執行成功後,在執行第二條SQL語句之前,程序被中斷了(可能地下光纖被挖掘機挖斷了……確實存在的哦),那麼李四的賬戶沒有加上1000元,而張三卻減去了1000元。這肯定是不行的!
你現在可能已經知道什麼是事務了吧!事務中的多個操作,要麼完全成功,要麼完全失敗!不可能存在成功一半的情況!也就是說給張三的賬戶減去1000元如果成功了,那麼給李四的賬戶加上1000元的操作也必須是成功的;否則給張三減去1000元,以及給李四加上1000元都是失敗的!
假如我們有一個表,為account,其內容為:
ID NAME BALANCE 1 zhangsan 10000 2 lisi 10000
public void transfer(boolean b) { 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); //操作 pstmt.setDouble(1, -10000);//為參數1賦值 pstmt.setInt(2, 1); //為參數2賦值 pstmt.executeUpdate(); // 在兩個操作中故意拋出異常,則事務失敗; if(b) { throw new Exception(); } pstmt.setDouble(1, 10000);//為參數1賦值 pstmt.setInt(2, 2);//為參數2賦值 pstmt.executeUpdate(); //提交事務 con.commit(); } catch(Exception e) { //回滾事務 if(con != null) { try { con.rollback(); } catch(SQLException ex) {} } throw new RuntimeException(e); } finally { //關閉 JdbcUtils.close(con, pstmt); } }
保存點是JDBC3.0的東西!需要數據庫服務器能夠支持保存點方式的回滾。校驗數據庫服務器是否支持保存點!
boolean b = con.getMetaData().supportsSavepoints();
保存點的作用是允許事務回滾到指定的保存點位置。在事務中設置好保存點,然後回滾時可以選擇回滾到指定的保存點,而不是回滾整個事務!注意,回滾到指定保存點並沒有結束事務!!!只有回滾了整個事務才算是結束事務了!
Connection類的設置保存點,以及回滾到指定保存點方法:
設置保存點:Savepoint setSavepoint();回滾到指定保存點:void rollback(Savepoint)。
/*
* 李四對張三說,如果你給我轉1W,我就給你轉100W。
* ==========================================
*
* 張三給李四轉1W(張三減去1W,李四加上1W)
* 設置保存點!
* 李四給張三轉100W(李四減去100W,張三加上100W)
* 查看李四余額為負數,那麼回滾到保存點。
* 提交事務
*/
@Test
public void fun() {
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);
//操作1(張三減去1W)
pstmt.setDouble(1, -10000);
pstmt.setString(2, "zs");
pstmt.executeUpdate();
//操作2(李四加上1W)
pstmt.setDouble(1, 10000);
pstmt.setString(2, "ls");
pstmt.executeUpdate();
// 設置保存點
Savepoint sp = con.setSavepoint();
//操作3(李四減去100W)
pstmt.setDouble(1, -1000000);
pstmt.setString(2, "ls");
pstmt.executeUpdate();
//操作4(張三加上100W)
pstmt.setDouble(1, 1000000);
pstmt.setString(2, "zs");
pstmt.executeUpdate();
//操作5(查看李四余額)
sql = "select balance from account where name=?";
pstmt = con.prepareStatement(sql);
pstmt.setString(1, "ls");
ResultSet rs = pstmt.executeQuery();
rs.next();
double balance = rs.getDouble(1);
//如果李四余額為負數,那麼回滾到指定保存點
if(balance < 0) {
con.rollback(sp);
System.out.println("張三,你上當了!");
}
//提交事務
con.commit();
} catch(Exception e) {
//回滾事務
if(con != null) {
try {
con.rollback();
} catch(SQLException ex) {}
}
throw new RuntimeException(e);
} finally {
//關閉
JdbcUtils.close(con, pstmt);
}
}
---完---