天天看點

JDBC 處理事務(11)

資料庫事務

1)在資料庫中,所謂事務是指一組邏輯操作單元,使資料從一種狀态變換到另一種狀态。

2)為確定資料庫中資料的一緻性,資料的操縱應該是離散的成組的邏輯單元:當它全部完成時,資料的一緻性可以保持,而當這個單元中的一部分操作失敗,整個事務應全部視為錯誤,所有從起始點以後的操作應全部回退到開始狀态

3)事務的操作:先定義開始一個事務,然後對資料做修改操作,這時如果送出(COMMIT),這些修改就永久地儲存下來,如果回退(ROLLBACK),資料庫管理系統将放棄所做的所有修改而回到開始事務時的狀态。

4)事務的ACID(acid)屬性

原子性:原子性是指事務是一個不可分割的工作機關,事務中的操作要麼都發生,要麼都不發生。

一緻性:事務必須使資料庫從一個一緻性狀态變換到另外一個一緻性狀态

隔離性:事務的隔離性是指一個事務的執行不能被其他事務幹擾,即一個事務内部的操作及使用的資料對兵法的其他事務是隔離的,并發執行的各個事務之間不能互相幹擾

持久性:持久性是指一個事務一旦被送出,它對資料庫中資料的改變就是永久性的,接下來的其他操作和資料庫故障不應該對其有任何影響

JDBC 事務處理

1)事務:指構成單個邏輯工作單元的操作集合

2)事務處理:保證所有事務都作為一個工作單元來執行,即使出現了故障,都不能改變這種執行方式。當在一個事務中執行多個操作時,要麼所有的事務都被送出(commit),要麼整個事務復原(rollback)到最初狀态

3)當一個連接配接對象被建立時,預設情況下是自動送出事務:每次執行一個SQL語句時,如果執行成功,就會向資料庫自動送出,而不能復原

4)為了讓多個SQL語句作為一個事務執行:

- 調用Connection對象的setAutoCommit(false);以取消自動送出事務

- 在所有的SQL語句都成功執行後,調用commit()方法送出事務

- 在出現異常時,調用rollback()方法復原事務

舉個例子

public class JDBCTest04 {
    /**
     * 違反事務一緻性
     * A 給 B 彙款 500 元
     */   
    public void testTransaction() throws SQLException, ClassNotFoundException {
        String driverClass = "com.mysql.jdbc.Driver";
        String jdbcurl = "";
        Connection connection = null;
        Class.forName(driverClass);
        connection = DriverManager.getConnection(jdbcurl,"user","password");
        PreparedStatement preparedStatement = null;
        String sql = "UPDATE users SET balance = " + "balance - 500 WHERE id = 1"; // A 賬号 - 500
        preparedStatement =  connection.prepareStatement(sql);
        preparedStatement.executeUpdate();
        int i = 10 / 0; // 第一條sql執行完成A賬号-500後,執行到這裡報錯導緻第二條sql沒有執行,進而違反了資料的一緻性
        System.out.println(i);
        sql = "UPDATE users SET balance = " + "balance + 500 WHERE id = 2";// B 賬号 + 500
        connection = DriverManager.getConnection(jdbcurl,"user","password");
        preparedStatement = connection.prepareStatement(sql);
        preparedStatement.executeUpdate();
    }
}           

複制

public class JDBCTest04 {   
    /**
     * 保證事務一緻性
     * A 給 B 彙款 500 元
     * 1. 如果多個操作,每個操作使用的是自己的單獨的連接配接,則無法保證事務
     * 2. 具體步驟:
     * 1)事務操作開始前,開始事務:取消connection的預設送出行為
     * connection.setAutoCommit(false)
     * 2)如果事務的操作都成功,則送出:connection.commit();
     * 3)復原事務:若出現異常,則在catch塊中復原事務
     */
    public void testTransaction01() throws SQLException {
        String driverClass = "com.mysql.jdbc.Driver";
        String jdbcurl = "";

        PreparedStatement preparedStatement = null;
        Connection connection = null;
        try {
            Class.forName(driverClass);
            connection = DriverManager.getConnection(jdbcurl,"user","password");
            connection.setAutoCommit(false);
            String sql = "UPDATE users SET balance = " + "balance - 500 WHERE id = 1";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.executeUpdate();
            int i = 10 / 0;
            sql = "UPDATE users SET balance = " + "balance + 500 WHERE id = 2";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.executeUpdate();
            connection.commit();
        }catch (Exception e){
            e.printStackTrace();
            try {
                connection.rollback();
            }catch (Exception e1){
                e.printStackTrace();
            }
        }finally {
            preparedStatement.close();
            connection.close();
        }
    }
}           

複制