JDBC | 第四章: JDBC之Transaction事務提交與回滾
阿新 • • 發佈:2020-08-24
預設情況下,當我們建立一個數據庫連線時,會執行在自動提交模式(Auto-commit)下。這意味著,任何時候我們執行一條SQL完成之後,事務都會自動提交。所以我們執行的每一條SQL都是一個事務,並且如果正在執行DML或者DDL語句,這些改變會在每一條SQL語句結束的時存入資料庫。有時候我們想讓一組SQL語句成為事務的一部分,那樣我們就可以在所有語句執行成功的時候提交,並且如果出現任何異常,這些語句作為事務的一部分,我們可以選擇將其全部回滾。
讓我們通過一個簡單的示例理解一下,這裡使用JDBC的事務管理來支援資料的完整性
/* * 發生異常回滾所有執行更新的sql * */ public void insrolledAll() { Connection connection = null; PreparedStatement preparedStatement = null; PreparedStatement preparedStatement1 = null; //這裡引數用?佔位符表示 String sqlTeacher = "insert into teacher ( name, age, hobby, addr) values (?,?,?,?)"; String sqlStudent = "insert into student (name, age, addr, hobby) values (?,?,?,?)"; try { //獲取資料連線 connection = basicUse.getConnection(); //設定事務自動提交為手動提交 connection.setAutoCommit(false); //獲取傳送sql指令執行sql進行預編譯 preparedStatement = connection.prepareStatement(sqlStudent); //設定sql語句引數索引從1開始 preparedStatement.setObject(1, "Tom"); preparedStatement.setObject(2, 24); preparedStatement.setObject(3, "上海"); preparedStatement.setObject(4, "籃球"); preparedStatement.executeUpdate(); System.out.println("執行sqlStudent" + sqlStudent); //手動製造異常 int i = 10 / 0; preparedStatement1 = connection.prepareStatement(sqlTeacher); preparedStatement1.setObject(1, "kenx"); preparedStatement1.setObject(2, 24); preparedStatement1.setObject(3, "足球"); preparedStatement1.setObject(4, "北京"); preparedStatement1.executeUpdate(); System.out.println("執行sqlTeacher" + sqlTeacher); //提交事務 connection.commit(); } catch (Exception e) { //回滾事務 try { connection.rollback(); System.out.println("JDBC Transaction rolled back successfully"); } catch (SQLException e1) { System.out.println("SQLException in rollback" + e1.getMessage()); e1.printStackTrace(); } e.printStackTrace(); } finally { //執行完資料庫操作後記得關閉資料庫連線資源 try { preparedStatement.close(); preparedStatement1.close(); connection.close(); } catch (SQLException e) { e.printStackTrace(); } } }
JDBC Savepoint示例
有時候一個事務可能是一組複雜的語句,因此可能想要回滾到事務中某個特殊的點。JDBC Savepoint幫我們在事務中建立檢查點(checkpoint),這樣就可以回滾到指定點。當事務提交或者整個事務回滾後,為事務產生的任何儲存點都會自動釋放並變為無效。把事務回滾到一個儲存點
/* * 發生異常回滾到指定的位置 * */ public void insrolledSavepoint() { Savepoint savepoint = null; Connection connection = null; PreparedStatement preparedStatement = null; PreparedStatement preparedStatement1 = null; //這裡引數用?佔位符表示 String sqlTeacher = "insert into teacher ( name, age, hobby, addr) values (?,?,?,?)"; String sqlStudent = "insert into student (name, age, addr, hobby) values (?,?,?,?)"; try { //獲取資料連線 connection = basicUse.getConnection(); //設定事務自動提交為手動提交 connection.setAutoCommit(false); //獲取傳送sql指令執行sql進行預編譯 preparedStatement = connection.prepareStatement(sqlStudent); //設定sql語句引數索引從1開始 preparedStatement.setObject(1, "JDBC"); preparedStatement.setObject(2, 24); preparedStatement.setObject(3, "上海"); preparedStatement.setObject(4, "籃球"); preparedStatement.executeUpdate(); System.out.println("執行sqlStudent" + sqlStudent); //設定回滾的點 失敗只會回滾老師資訊 savepoint = connection.setSavepoint("teacher"); preparedStatement1 = connection.prepareStatement(sqlTeacher); preparedStatement1.setObject(1, "kenx"); preparedStatement1.setObject(2, 24); preparedStatement1.setObject(3, "足球"); preparedStatement1.setObject(4, "北京"); preparedStatement1.executeUpdate(); System.out.println("執行sqlTeacher" + sqlTeacher); //手動製造異常 int i = 10 / 0; //提交事務 connection.commit(); } catch (Exception e) { //回滾事務 try { if (StrUtil.isEmptyIfStr(savepoint)) { //回滾所有更新sql connection.rollback(); System.out .println("JDBC Transaction rolled back successfully"); } else { connection.rollback(savepoint); System.out.println("JDBC Transaction rolled back successfully"); connection.commit(); } } catch (SQLException e1) { System.out.println("SQLException in rollback" + e1.getMessage()); e1.printStackTrace(); } e.printStackTrace(); } finally { //執行完資料庫操作後記得關閉資料庫連線資源 try { preparedStatement.close(); preparedStatement1.close(); connection.close(); } catch (SQLException e) { e.printStackTrace(); } } }
完整專案案例
點選這裡 github