1. 程式人生 > 實用技巧 >JDBC | 第四章: JDBC之Transaction事務提交與回滾

JDBC | 第四章: JDBC之Transaction事務提交與回滾

預設情況下,當我們建立一個數據庫連線時,會執行在自動提交模式(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