事務的四大特性ACID

 

相關歷史文章(閱讀本文之前,您可能需要先看下之前的系列👇

分佈式事務「2020年」必學,升職加薪你準備好了嗎?

事務的基本概念

 

前言

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

       事務的四大特性主要是:原子性(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的話,那麼在另外一個線程發起查詢請求的話,那麼並不能查看到最近的數據(這裏未進行編碼),這就是隔離性。

 

分佈式事務解決方案「手寫代碼」:http://t.cn/AieNUirK

點擊「閱讀原文」,快人一步,快速學習分佈式事務! 

發佈了131 篇原創文章 · 獲贊 142 · 訪問量 68萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章