java事務的四大特性ACID


前言

       對於要把事務在實際中使用好,需要了解事務的特性。

       事務的四大特性主要是:原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、持久性(Durability)。

 

一、事務的四大特性

1.1 原子性(Atomicity)

原子性是指事務是一個不可分割的工作單位,事務中的操作要么全部成功,要么全部失敗。比如在同一個事務中的SQL語句,要么全部執行成功,要么全部執行失敗。

 

begin transaction;
    update account set money = money-100 where name = '張三';
    update account set money = money+100 where name = '李四';
commit transaction;

 

1.2 一致性(Consistency)

官網上事務一致性的概念是:事務必須使數據庫從一個一致性狀態變換到另外一個一致性狀態。

       換一種方式理解就是:事務按照預期生效,數據的狀態是預期的狀態。

       舉例說明:張三向李四轉100元,轉賬前和轉賬后的數據是正確的狀態,這就叫一致性,如果出現張三轉出100元,李四賬號沒有增加100元這就出現了數據錯誤,就沒有達到一致性。

 

1.3 隔離性(Isolation)

事務的隔離性是多個用戶並發訪問數據庫時,數據庫為每一個用戶開啟的事務,不能被其他事務的操作數據所干擾,多個並發事務之間要相互隔離。

 

1.4 持久性(Durability)

持久性是指一個事務一旦被提交,它對數據庫中數據的改變就是永久性的,接下來即使數據庫發生故障也不應該對其有任何影響。

       例如我們在使用JDBC操作數據庫時,在提交事務方法后,提示用戶事務操作完成,當我們程序執行完成直到看到提示后,就可以認定事務以及正確提交,即使這時候數據庫出現了問題,也必須要將我們的事務完全執行完成,否則就會造成我們看到提示事務處理完畢,但是數據庫因為故障而沒有執行事務的重大錯誤。

 

二、數據庫ACID的體現

2.1 原子性

       原子性說的是數據要么一起成功,要么一起失敗,那么就有兩種情況:事務提交(commit)和事務回滾(rollback)。

       我們先看下事務正常提交的情況,下面我們在數據庫模擬張三給李四轉賬成功的場景:

 

 

我們手動提交(commit)數據庫事務之后,張三給李四轉賬100元的這個業務操作算是真正成功了,張三賬戶中少了100,李四賬戶中多了100。

       接下來看下事務不正常的情況下:

 

       事務回滾之后,對於張三和李四的金額的操作都失敗了,這就確保了事務的原子性。

 

2.2 一致性

       一致性主要說明的是事務的前后,數據庫中的數據的狀態要確保一致。

事務提交成功,那么張三賬戶上的余額是900元,李四賬戶上的余額是100元。

事務提交失敗,那么張三和李四的賬戶的金額不變。

       這說明現在在數據庫的事務的控制下,確保了數據的一致性。

 

2.3 隔離性

       隔離性的體現,多個並發事務之間是隔離的。

       張三給李四轉賬,如果事務沒有提交的話,那么在另外一個session中並不能查看另外一個session未提交的數據。

 

 

 

2.4 持久性

       持久性的體現就是數據一旦commit之后,那么對於數據的改變就是永久的。我們commit之后,張三的賬戶就永久減少了100元,李四的賬戶就永久增加了100元。

 

三、JDBC ACID的體現

       我們使用JDBC連接MYSQL數據庫的代碼:

 

public class App {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        /*
         * 1/ 注冊JDBC驅動; 
         * 2/ 獲取連接; 
         * 3/ 開啟事務
         * 4/ 創建SQL語句; 
         * 5/ 執行SQL語句; 
         * 6/ 提交事務
         * 7/ 關閉連接.
         * 
         */
        // 1/ 注冊JDBC驅動;
        Class.forName("com.mysql.cj.jdbc.Driver");

        String url = "jdbc:mysql://127.0.0.1:3306/tx_demo";
        String user = "root";
        String password = "root";

        // 2/ 獲取連接;
        Connection conn = DriverManager.getConnection(url, user, password);

        // 3/ 開啟事務
        conn.setAutoCommit(false);

        // 4/ 創建SQL語句; 注意:實際使用account的主鍵,這里主要是為了方便理解。
        String sql = "update account set money = money-100 where name = ?";
        PreparedStatement ps = conn.prepareStatement(sql);
        ps.setString(1,"張三");

        // 5/ 執行SQL語句; 
        int rs = ps.executeUpdate();
        if(rs>0) {
            System.out.println("張三-扣減成功");
        }

        // 給李四增加金額
        sql = "update account set money = money+100 where name = ?";
        ps = conn.prepareStatement(sql);
        ps.setString(1,"李四");
        rs = ps.executeUpdate();
        if(rs>0) {
            System.out.println("李四-增加成功");
        }

        // 6/ 提交事務,更標准的寫法應該攔截異常,有異常的情況下rollback();
        conn.commit();

        // 7/ 關閉連接.
        ps.close();
        conn.close();
    }
}

說明:

如果代碼正常運行的話,那么張三會扣減金額,李四會增加金額,這就確保的原子性;

 一旦數據保存到數據庫之后,數據就永久被改變了,這就是持久性;

事務前后,數據的狀態也是我們所期望的狀態,這就保證了數據的一致性;

如果在事務未commit的話,那么在另外一個線程發起查詢請求的話,那么並不能查看到最近的數據(這里未進行編碼),這就是隔離性。


免責聲明!

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



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