Java Web(八) 事務,安全問題及隔離級別


事務

什么是事務?

事務就是一組原子性的SQL查詢,或者說是一個獨立的工作單元。

事務的作用

事務在我們平常的CRUD(增刪改查)操作當中也許不太常用, 但是如果我們有一種需求,一組操作中必須全部成功執行,才算完成任務,只要有一個出錯了,那么所有的任務都將回到最初的狀況,恢復原樣。那么這就需要使用事務了。如: 銀行轉賬,購買飛機票......

事務的特性

事務具有4個特性(ACID):原子性(Atomicity)、一致性(Consistency)、隔離性(lsolation)、持久性(Durability)。

  • 原子性(Atomicity): 事務中的邏輯要全部執行,不可分割。(原子是物理中最小單位)
  • 一致性(Consistency): 指事務執行前和執行后, 數據的完整性保持一致
  • 隔離性(Isolation): 指一個事務在執行的過程中不應該受其他事務的影響
  • 持久性(Durability): 事務執行結束(提交或回滾), 數據都應持久化到數據中

演示事務

在MySQL命令行的默認設置下,事務都是自動提交的,即執行SQL語句后就會馬上執行commit操作。因此要顯式地開啟一個事務務須使用命令begin或start transaction,或者執行命令set autocommit = 0,用來禁止使用當前會話的自動提交。

  1. 命令行中演示事務

    開啟事務:start transaction;

    提交事務:commit;  數據將會寫到磁盤上的數據庫

    回滾事務:rollback;  數據回滾,回到最初的狀態。

    開啟一個事物:

    img

    我們先看看stuifo表里最初的數據:

    img

    再更新stuifo表里的派大星的性別為女並查看修改后的數據:

    img

    這里顯示性別已經修改了,但其實數據沒有真正的寫入到硬盤中,我們去MySQL管理軟件看看數據有沒有被更新:

    img

    可以發現數據沒有被更新,因為事務沒有被提交,現在我們把事務提交。

    img

    提交后,數據才會被更新,真正的寫入到硬盤里。

    img

    如果不提交,使用回滾rollback,數據就會恢復到初始狀態:

    img

  2. 使用代碼演示事務

    package test;
    
    import Utils.JDBCUtils;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.SQLException;
    
    public class demo {
        public static void main(String[] args) {
            Connection conn = null;
            PreparedStatement ps = null;
            try {
                conn = JDBCUtils.getConnection();
                conn.setAutoCommit(false);//關閉事務默認自動提交
                String sql = "update stuifo set sex = '女' where id = 2";
                ps = conn.prepareStatement(sql);
                ps.executeUpdate();
                conn.commit();//成功,提交事務
            } catch (SQLException e) {
                try {
                    conn.rollback();//失敗,回滾事務
                } catch (SQLException e1) {
                    e1.printStackTrace();
                }
                e.printStackTrace();
            } finally {
                JDBCUtils.closeStatement(ps);
                JDBCUtils.closeConn(conn);
            }
        }
    }
    

安全問題

讀問題

在操作數據庫時,可能會出現讀問題,主要表現為臟讀,不可重復讀,幻讀。

  1. 臟讀

    臟讀: 指 一個事務讀到了另一個事務還未提交的數據。

    演示:

    最初stuifo表中的數據為:

    img

    在兩個窗口分別開啟一個事務,首先在A窗口修改派大星性別為女,但不提交事務,然后在B窗口中查詢表stuifo。

    A窗口:

    img

    B窗口:

    img

    這樣B窗口中的事務就讀取到了A窗口中的事務未提交的數據,稱之為臟讀。

  2. 不可重復讀

    不可重復讀: 一個事務讀到了另一個事務提交的數據, 導致多次查詢結果不一致。

    最初stuifo表中的數據為:

    img

    mysql默認是可重復讀的,所以我們先把A窗口的隔離級別設置為讀未提交,在兩個窗口分別開啟一個事物,首先在A窗口查詢表stuifo,然后在B窗口中修改派大星性別為女,並提交事務,再在A窗口查詢表stuifo。

    A窗口:

    img

    B窗口:

    img

    A窗口:

    img

    這樣A窗口中在一個事務下前后讀取的數據不一致,稱為不可重復讀。

  3. 幻讀

    幻讀: 一個事務讀到了另一個事務已提交的插入的數據,導致多次查詢結果不一致。

    幻讀與不可重復讀類似,都是前后查詢結果不一致,但是不可重復讀針對的是update,后者針對的是insert。

寫問題

在操作數據庫時,可能會出現寫問題,主要表現為丟失更新。

丟失更新:指一個事務去修改數據庫,另一個事務也修改數據庫,最后的那個事務,不管是提交還是回滾都會造成前面一個事務的數據更新丟失。

img

解決丟失更新,通常有兩種方法:悲觀鎖和樂觀鎖。

  • 悲觀鎖  

    指事務在一開始就認為丟失更新一定會發生,這是一件很悲觀的事情。具體操作步驟如下:

    1.所有事務在執行操作前,先查詢一次數據,查詢語句如下:

    select * from student for update ; 后面的for update其實是數據庫鎖機制 、一種排他鎖。

    2.哪個事務先執行這個語句,哪個事務就持有了這把鎖,可以查詢出來數據,后面的事務再執行這條語句,不會有任何數據顯示,就只能等着。

    3.一直等到前面的那個事務提交數據后,后面的事務數據才會出來,那么才可以往下接着操作。

這相當於上衛生間似的,誰先來誰就進去蹲着,后面來的人都只能等着。只有里面的人出來了,外面的人才能進去。

  • 樂觀鎖

    樂觀鎖是指,從來不會覺得丟失更新會發生。那么它的具體做法是什么呢?

    要求程序員在數據庫中添加字段,然后在后續更新的時候,對該字段進行判定比對,如果一致才允許更新。例子如下:

    1.數據庫表中,額外添加了一個version字段,用於記錄版本,默認從0開始,只要有針對表中數據進行修改的,那么version就+1。

    2.開啟A事務,然后開啟B事務。

    3.先執行數據庫表操作。因為以前都沒有人修改過。所以是允許A事務修改數據庫的,但是修改完畢,就把version的值變成1了。

    4.B事務,這時候如果想執行修改,那么是不允許修改的。因為B事務以前是沒有查詢過數據庫內容的,所以它認為數據庫版本還是0。但是數據庫的版本經過A修改,已經是1了。所以這時候不允許修改,要求其重新查詢 。

    5.B重新查詢后,將會得到version為1的數據,這份數據就是之前A事務修改的數據了,B在進行修改,也是在A的基礎上修改的。所以就不會有丟失更新的情況出現了。

隔離級別

設置事務的隔離級別可以解決上面的臟讀,不可重復讀,幻讀問題,但是隔離級別越高,執行效率越低,mysql的隔離級別默認為可重復讀。

事務隔離分為四個級別,由低到高為讀未提交(Read uncommitted)、讀提交(read committed)、可重復讀(repeatable read)和串行化(Serializable)。

✔代表可能發生,✖代表不會發生

隔離級別 臟讀 不可重復讀 幻讀
讀未提交(Read uncommitted)
讀提交(read committed)
可重復讀(repeatable read)
串行化(Serializable)

查看隔離級別:

img

設置隔離級別:

img


免責聲明!

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



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