在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); } }
---完---