1. 程式人生 > 其它 >MySQL之senior(十)——事務

MySQL之senior(十)——事務

MySQL之senior(十)——事務

定義

  1. 一個事務其實就是一個完整的業務邏輯。是一個最小的工作單元。不可再分。 什麼是一個完整的業務邏輯? 假設轉賬,從A賬戶向B賬戶中轉賬10000. 將A賬戶的錢減去10000(update語句) 將B賬戶的錢加上10000(update語句) 這就是一個完整的業務邏輯。

    以上的操作是一個最小的工作單元,要麼同時成功,要麼同時失敗,不可再分。 這兩個update語句要求必須同時成功或者同時失敗,這樣才能保證錢是正確的。

  2. 只有DML語句(insert delete update) 才會有事務這一說,其它語句和事務無關! 因為 只有以上的三個語句是資料庫表中資料進行增、刪、改的。

    只要你的操作一旦涉及到資料的增、刪、改,那麼就一定要考慮安全問題。

  3. 假設所有的業務,只要一條DML語句就能完成,還有必要存在事務機制嗎? 正是因為做某件事的時候,需要多條DML語句共同聯合起來才能完成, 所以需要事務的存在。如果任何一件複雜的事兒都能一條DML語句搞定, 那麼事務則沒有存在的價值了。

    到底什麼是事務呢? 說到底,說到本質上,一個事務其實就是多條DML語句同時成功,或者同時失敗! 事務:就是批量的DML語句同時成功,或者同時失敗!

  4. 事務是怎麼做到多條DML語句同時成功和同時失敗的呢? InnoDB儲存引擎:提供一組用來記錄事務性活動的日誌檔案

    在事務的執行過程中,每一條DML的操作都會記錄到“事務性活動的日誌檔案”中。

    在事務的執行過程中,我們可以提交事務,也可以回滾事務。

    提交事務: 清空事務性活動的日誌檔案,將資料全部徹底持久化到資料庫表中。 提交事務標誌著,事務的結束。並且是一種全部成功的結束。

    回滾事務: 將之前所有的DML操作全部撤銷,並且清空事務性活動的日誌檔案 回滾事務標誌著,事務的結束。並且是一種全部失敗的結束。

  1. 怎麼提交事務,怎麼回滾事務? 提交事務:commit; 語句 回滾事務:rollback; 語句(回滾永遠都是隻能回滾到上一次的提交點!commit點)

    事務對應的英語單詞是:transaction

    在mysql當中預設的事務行為是怎樣的? mysql預設情況下是支援自動提交事務的。(自動提交)

    自動提交:每執行一條DML語句,則提交一次!

    這種自動提交實際上是不符合我們的開發習慣,因為一個業務通常是需要多條DML語句共同執行才能完成的,為了保證資料的安全,必須要求同時成功之後再提交,所以不能執行一條就提交一條。

    怎麼將mysql的自動提交機制關閉掉呢? 先執行這個命令:start transaction;

  1. 事務包括4個特性?

    A:原子性  atomic
        說明事務是最小的工作單元。不可再分。
    ​
    C:一致性  concordant
        所有事務要求,在同一個事務當中,所有操作必須同時成功,或者同時失敗,
        以保證資料的一致性。
    ​
    I:隔離性  isolated
        A事務和B事務之間具有一定的隔離。
        教室A和教室B之間有一道牆,這道牆就是隔離性。
        A事務在操作一張表的時候,另一個事務B也操作這張表會那樣???
    ​
    D:永續性  durable
        事務最終結束的一個保障。事務提交,就相當記憶體上的資料
        儲存到硬碟上!
  1. 重點研究事務的隔離性!!(檢視隔離級別:SELECT @@transaction_isolation )

    A教室和B教室中間有一道牆,這道牆可以很厚,也可以很薄。這就是事務的隔離級別。
    這道牆越厚,表示隔離級別就越高。
    ​
    事務和事務之間的隔離級別:4個級別
    ​
        讀未提交:read uncommitted(最低的隔離級別)《沒有提交就讀到了》
            什麼是讀未提交?
                事務A可以讀取到事務B未提交的資料。
            這種隔離級別存在的問題就是:
                髒讀現象!(Dirty Read)
                我們稱讀到了髒資料。
            這種隔離級別一般都是理論上的,大多數的資料庫隔離級別都是二檔起步!
    ​
        讀已提交:read committed《提交之後才能讀到》
            什麼是讀已提交?
                事務A只能讀取到事務B提交之後的資料。
            這種隔離級別解決了什麼問題?
                解決了髒讀的現象。
            這種隔離級別存在什麼問題?
                不可重複讀取資料。
                什麼是不可重複讀取資料呢?
                    在事務開啟之後,第一次讀到的資料是3條,當前事務還沒有
                    結束,可能第二次再讀取的時候,讀到的資料是4條,3不等於4
                    稱為不可重複讀取。
    ​
            這種隔離級別是比較真實的資料,每一次讀到的資料是絕對的真實。
            oracle資料庫預設的隔離級別是:read committed
    ​
        可重複讀:repeatable read《提交之後也讀不到,永遠讀取的都是剛開啟事務時的資料》
            什麼是可重複讀取?
                事務A開啟之後,不管是多久,每一次在事務A中讀取到的資料
                都是一致的。即使事務B將資料已經修改,並且提交了,事務A
                讀取到的資料還是沒有發生改變,這就是可重複讀。
            可重複讀解決了什麼問題?
                解決了不可重複讀取資料。
            可重複讀存在的問題是什麼?
                可以會出現幻影讀。
                每一次讀取到的資料都是幻象。不夠真實!
            
            早晨9點開始開啟了事務,只要事務不結束,到晚上9點,讀到的資料還是那樣!
            讀到的是假象。不夠絕對的真實。
    ​
            mysql中預設的事務隔離級別就是這個!!!!!!!!!!!
    ​
        序列化/序列化:serializable(最高的隔離級別)
            這是最高隔離級別,效率最低。解決了所有的問題。
            這種隔離級別表示事務排隊,不能併發!
            synchronized,執行緒同步(事務同步)
            每一次讀取到的資料都是最真實的,並且效率是最低的。
  1. 驗證各種隔離級別

    被測試的表t_user
    ​
    驗證:read uncommited
    mysql> set global transaction isolation level read uncommitted;
    ​
    事務A                                             事務B
    --------------------------------------------------------------------------------
    ​
    use bjpowernode;
                                                        use bjpowernode;
    start transaction;
    select * from t_user;
                                                        start transaction;
                                                        insert into t_user values('zhangsan');
    select * from t_user;
    ​
    ​
    ​
    ​
    驗證:read commited
    mysql> set global transaction isolation level read committed;
    ​
    事務A                                             事務B
    --------------------------------------------------------------------------------
    ​
    use bjpowernode;
                                                        use bjpowernode;
    start transaction;
                                                        start transaction;
    select * from t_user;
                                                        insert into t_user values('zhangsan');
    select * from t_user;
                                                        commit;
    select * from t_user;
    ​
    ​
    ​
    ​
    驗證:repeatable read
    mysql> set global transaction isolation level repeatable read;
    ​
    事務A                                             事務B
    --------------------------------------------------------------------------------
    ​
    use bjpowernode;
                                                        use bjpowernode;
    start transaction;
                                                        start transaction;
    select * from t_user;
                                                        insert into t_user values('lisi');
                                                        insert into t_user values('wangwu');
                                                        commit;
    select * from t_user;
    ​
    ​
    ​
    ​
    驗證:serializable
    mysql> set global transaction isolation level serializable;
    ​
    事務A                                             事務B
    --------------------------------------------------------------------------------
    ​
    use bjpowernode;
                                                        use bjpowernode;
    start transaction;
                                                        start transaction;
    select * from t_user;
    insert into t_user values('abc');
                                                        select * from t_user;