使用JDBC進行數據庫的事務操作(2)


  本篇將講訴如何使用JDBC進行數據庫有關事務的操作。在上一篇博客中已經介紹了事務的概念,和在MySQL命令行窗口進行開啟事務,提交事務以及回滾事務的操作。

  似乎事務和批處理都可以一次同時執行多條SQL命令,但是事務是如果某一條SQL出錯,則前面已經執行過的SQL全部都將回滾;而批處理中某一條SQL出錯,那么這條出錯的SQL要么會拋出個異常,要么以一個代表出錯的值返回,已經執行過的SQL不受影響,至於后面的SQL是否還會執行則看數據庫,不同數據庫有不同的處理。

  在前一篇我們說過,數據庫對於事務是默認自動提交的,也就是發一條SQL命令則數據庫就執行一條。而對於JDBC而言,當向數據庫獲取一個鏈接Connection對象,在默認情況下通過Connection對象發送的SQL命令也是默認自動提交事務的。

操作:

  ① 如果我們想使用JDBC對多條SQL進行整體執行,需要先提交事務命令,這一步是通過Connection對象先將自動提交關閉,調用Connection對象的setAutoCommit(false)方法即可。這個方法相當於在MySQL命令行窗口中輸入”start transaction”命令。

  ② 如果我們在JDBC已經將自動提交關閉的情況下需要提交事務,則調用Connection對象的commit()方法即可。

  ③ 如果我們在JDBC已經將自動提交關閉的情況下需要回滾事務,則調用Connection對象的rollback(…)方法即可。rollback方法如果是無參,則回滾前面所有已執行的SQL命令;如果是有參,則可以指定回滾點,保留前面部分指定的已執行的SQL命令。

  下面以幾個案例來像上一篇博客一樣分別介紹幾種事務的相關操作。

例1:正確提交事務的小案例

  在這個簡單的案例中,通過用戶A向用戶B轉賬100元來快速了解如何使用JDBC操作事務。

創建數據庫和表,另外再添加兩條數據:

    create database jdbcdemo; use jdbcdemo; create table account(  id int primary key auto_increment,   name varchar(40),   money double ); insert into account(name,money) values('a',1000); insert into account(name,money) values('b',1000);

先看看准備的數據:

  

創建工程,在工程中導入數據庫連接驅動的jar包。在【src】目錄下新建一個database.properties文件,內容如下:

    driver=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/jdbcdemo
    username=root
    password=root

構建JDBC的工具類,包括注冊驅動,獲取連接,釋放資源和連接等,這部分同《JDBC操作數據庫的學習(2)》中相同,此處略。

使用JDBC完成事務操作的demo代碼如下:

 1 public void transaction() throws SQLException {  2         Connection conn = null;  3         PreparedStatement st = null;  4         ResultSet rs = null;  5         try{  6             conn = JdbcUtils.getConnection();  7             conn.setAutoCommit(false);  //開啟事務,相當於start transaction命令
 8             
 9             String sql1 = "update account set money=money-100 where name='a'"; 10             st = conn.prepareStatement(sql1); 11             st.executeUpdate();     //執行SQL語句
12             
13             String sql2 = "update account set money=money+100 where name='b'"; 14             st = conn.prepareStatement(sql2); 15             st.executeUpdate();    //執行SQL語句
16             
17             conn.commit();   //提交事務
18         }finally{ 19  JdbcUtils.release(conn, st, rs); 20  } 21     }
View Code

查看事務執行情況:

  

通過例1中簡單的代碼就完成了事務的一系列操作。可以看到用戶A向用戶B確實轉賬了100元。

例2:事務執行過程出錯回滾的小案例

  通過前一篇博客,我們知道如果在事務執行過程中發生了錯誤,則數據庫將會使該事務中所有的操作都回滾,那么我們在使用JDBC的情況下也來重新模擬一次,依然還是用戶A向用戶B轉賬100元。

  將例1中的account表所有用戶的金額重新制定為1000元的SQL命令:

    update account set money=1000;

  

創建工程,在工程中導入數據庫連接驅動的jar包。在【src】目錄下新建一個database.properties文件,內容如下:

    driver=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/jdbcdemo
    username=root
    password=root

構建JDBC的工具類,包括注冊驅動,獲取連接,釋放資源和連接等,這部分同《JDBC操作數據庫的學習(2)》中相同,此處略。

在使用JDBC進行事務處理中,我們添加一個顯而易見的錯誤:int x = 1/0 ,如下代碼:

 1 public void transaction() throws SQLException {  2         Connection conn = null;  3         PreparedStatement st = null;  4         ResultSet rs = null;  5         try{  6             conn = JdbcUtils.getConnection();  7             conn.setAutoCommit(false);  //開啟事務,相當於start transaction命令
 8             
 9             String sql1 = "update account set money=money-100 where name='a'"; 10             st = conn.prepareStatement(sql1); 11  st.executeUpdate(); 12             
13             int x = 1/0;      //在此處模擬事務處理過程中出錯
14             
15             String sql2 = "update account set money=money+100 where name='b'"; 16             st = conn.prepareStatement(sql2); 17  st.executeUpdate(); 18             
19             conn.commit();   //提交事務
20         }finally{ 21  JdbcUtils.release(conn, st, rs); 22  } 23     }
View Code

  當我們執行這個Java方法時,由於設置了int x = 1/0這個邏輯錯誤,程序會拋出異常,但是因為拋出異常后,后面的代碼不再執行,也就是說程序無法執行到提交事務conn.commit()方法處,因此數據庫將會回滾該事務所有的操作,因此A與B的金額還是原來那樣:

  

例3:事務執行過程出錯由開發者手動回滾的小案例

  在例2中當事務執行過程中出錯時,會由數據庫自動回滾所有的操作,而在JDBC中,我們也可以調用鏈接Connection對象的rollback()方法回滾所有的操作,在下面的案例中,我們將在捕獲異常的代碼塊中手動回滾所有的操作。

  所有表、表中數據、配置文件和JDBC工具類都同例2相同。

  將例2中的代碼修改為如下:

 1 public void transaction() throws SQLException {  2         Connection conn = null;  3         PreparedStatement st = null;  4         ResultSet rs = null;  5         try{  6             conn = JdbcUtils.getConnection();  7             conn.setAutoCommit(false);  //開啟事務,相當於start transaction命令
 8             
 9             String sql1 = "update account set money=money-100 where name='a'"; 10             st = conn.prepareStatement(sql1); 11  st.executeUpdate(); 12             
13             int x = 1/0;      //在此處模擬事務處理過程中出錯
14             
15             String sql2 = "update account set money=money+100 where name='b'"; 16             st = conn.prepareStatement(sql2); 17  st.executeUpdate(); 18             
19             conn.commit();   //提交事務
20         }catch (Exception e) { 21  e.printStackTrace(); 22             conn.rollback();    //手動回滾該事務中所有的操作
23         }finally{ 24  JdbcUtils.release(conn, st, rs); 25  } 26     }
View Code

  效果和例2也是一樣的,事務出錯則回滾所有的操作。

例4:指定事務回滾點的案例

  例3的手動回滾其實有些雞肋,與其說是手動回滾,其實即使沒有調用rollback該事務就不會執行成功,而rollback方法更高級的功能在於能回滾到指定的地方。

  通過鏈接Connection對象的setSavepoint()方法即可在該方法所在的位置設置回滾點對象,當調用rollback(回滾點對象)方法即可將事務回滾到這個位置。這樣在執行回滾之后,再次調用提交事務(Commit),則回滾點之前的SQL還是執行的。

  以例2為前提,我們在會發生異常地方的前面設置回滾點,而使第一條SQL語句能被執行,即用戶A的操作能執行(減少100),用戶B的操作不能執行(金額不變)。

  所有表、表中數據、配置文件和JDBC工具類都同例2相同。

將例2中的代碼修改為如下:

 1 public void transaction() throws SQLException {  2         Connection conn = null;  3         PreparedStatement st = null;  4         ResultSet rs = null;  5         Savepoint sp = null;   //代表回滾點對象
 6         try{  7             conn = JdbcUtils.getConnection();  8             conn.setAutoCommit(false);  //開啟事務,相當於start transaction命令
 9             
10             String sql1 = "update account set money=money-100 where name='a'"; 11             st = conn.prepareStatement(sql1); 12  st.executeUpdate(); 13             
14             sp = conn.setSavepoint();   //在此處設置回滾點
15             
16             int x = 1/0;      //在此處模擬事務處理過程中出錯
17             
18             String sql2 = "update account set money=money+100 where name='b'"; 19             st = conn.prepareStatement(sql2); 20  st.executeUpdate(); 21             
22             conn.commit();   //提交事務
23         }catch (Exception e) { 24             conn.rollback(sp);    //回滾到指定的回滾點處
25             conn.commit();        //回滾之后再次提交事務保證回滾點之前的SQL能被執行
26             
27         }finally{ 28  JdbcUtils.release(conn, st, rs); 29  } 30     }
View Code

查看事務執行情況:

  

  可以看到結果正如我們希望的那樣,由於用戶A的操作在回滾點之前,又因為執行回滾之后還執行了提交事務,因此回滾點之前的SQL命令還是可以被執行成功的。因此切記,要想使用回滾點,一定要在回滾之后再次提交事務,否則設置回滾點是沒有意義的。

  下圖是一張上面例子的執行流程:

  

 

 

 

              

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM