<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Mysql四種事務(wù)隔離級(jí)別

          共 5727字,需瀏覽 12分鐘

           ·

          2021-02-02 09:24

          點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號(hào)”

          優(yōu)質(zhì)文章,第一時(shí)間送達(dá)

          ? 作者?|? 玉樹臨楓

          來源 |? urlify.cn/jmM3ya

          76套java從入門到精通實(shí)戰(zhàn)課程分享

          一、前提

            時(shí)過一年重新拾起博文記錄,希望后面都能堅(jiān)持下來。接著之前MySql的學(xué)習(xí),先記錄下這篇。

            以下都是基于mysql8 innodb存儲(chǔ)引擎進(jìn)行分析的。  


          二、事務(wù)的ACID特性

          1. A(Atomicity) 原子性

            指整個(gè)數(shù)據(jù)庫(kù)事務(wù)是不可分割的單位,整個(gè)事務(wù)中的所有操作要么全部提交成功,要么全部失敗回滾。只有使事務(wù)中所有的數(shù)據(jù)庫(kù)操作都執(zhí)行成功,才算整個(gè)事務(wù)執(zhí)行成功。否則事務(wù)中任何一個(gè)SQL語句執(zhí)行失敗,那么這個(gè)事務(wù)就是執(zhí)行失敗的, 已執(zhí)行成功的SQL語句也必須撤銷,數(shù)據(jù)庫(kù)狀態(tài)應(yīng)該退回到執(zhí)行事務(wù)前的狀態(tài)。

          1. C(consistency) 一致性

            一致性事務(wù)將數(shù)據(jù)庫(kù)從一種狀態(tài)轉(zhuǎn)變?yōu)橄乱环N一致的狀態(tài)。在事務(wù)開始之前和事務(wù)結(jié)束以后,數(shù)據(jù)庫(kù)的完整性約束沒有被破壞。

            例如:在表中有個(gè)字段為姓名為唯一約束,即在表中姓名不能重復(fù)。如果一個(gè)事務(wù)對(duì)姓名字段進(jìn)行了修改,但是在事務(wù)提交或事務(wù)操作發(fā)生回滾后,表中的姓名變得非唯一了,這就破壞了事務(wù)的一致性要求,即事務(wù)將數(shù)據(jù)從一種狀態(tài)變?yōu)榱艘环N不一致的狀態(tài)。

          1. I(isolation) 隔離性

            事務(wù)的隔離性要求每個(gè)讀寫事務(wù)的對(duì)象對(duì)其他事務(wù)的操作對(duì)象能相互分離,即該事務(wù)提交前對(duì)其他事務(wù)都不可見。通常可以使用鎖來實(shí)現(xiàn)。

          1. D(durability) 持久性

            事務(wù)一旦提交,其結(jié)果就是永久性的。即使發(fā)生宕機(jī)等故障,數(shù)據(jù)庫(kù)也能將數(shù)據(jù)恢復(fù)。

            需要注意的是:只能從事務(wù)本身的角度來保證結(jié)果的永久性,例如:在事務(wù)提交后,所有變化都是永久的。即使當(dāng)數(shù)據(jù)因?yàn)楸罎⒍枰謴?fù)時(shí),也能保證恢復(fù)后提交的數(shù)據(jù)都不會(huì)丟失。但如果不是數(shù)據(jù)庫(kù)本身發(fā)生故障,而是一些外部的原因?qū)е聰?shù)據(jù)庫(kù)發(fā)生問題,則有可能是提交的數(shù)據(jù)丟失(RAID卡損壞)。

            因此持久性保證事務(wù)系統(tǒng)的高可靠性,而不是高可用性。對(duì)于高可用性的實(shí)現(xiàn),事務(wù)本身并不能保證,需要一些系統(tǒng)共同配合完成。

          三、事務(wù)的4種隔離級(jí)別

          • Read Uncommitted - 未提交讀

            在該隔離級(jí)別下的事務(wù)會(huì)讀取到其未提交事務(wù)的數(shù)據(jù),此種現(xiàn)象也稱之為臟讀

          步驟事務(wù)1事務(wù)2
          1

          設(shè)置隔離級(jí)別

          mysql> set @@session.transaction_isolation 
          = 'READ-UNCOMMITTED';
          Query OK,
          0 rows affected (0.00 sec)

          mysql
          > select @@transaction_isolation;
          +-------------------------+
          | @@transaction_isolation |
          +-------------------------+
          | READ-UNCOMMITTED |
          +-------------------------+
          1 row in set (0.00 sec)


          2

          開啟事務(wù)1

          mysql> begin;
          Query OK,
          0 rows affected (0.00 sec)

          mysql
          > select * from t;
          Empty
          set (0.00 sec)

          3

          無需管隔離級(jí)別,只開啟事務(wù)2并插入記錄

          mysql> begin;
          Query OK,
          0 rows affected (0.00 sec)

          mysql
          > insert into t select 1, '1';
          Query OK,
          1 row affected (0.00 sec)
          Records:
          1 Duplicates: 0 Warnings: 0

          ?4

          此時(shí)能查到事務(wù)2中未提交事務(wù)中的數(shù)據(jù),這就是臟讀。

          mysql> select * from t;
          +------+------+
          | id | name |
          +------+------+
          | 1 | 1 |
          +------+------+
          1 row in set (0.00 sec)


            注意:設(shè)置隔離級(jí)別之前,記得查看當(dāng)前隔離級(jí)別的key, 有可能版本不一樣對(duì)應(yīng)的key不一樣。(另外表可以自己隨意選擇)

          1 mysql> show variables like '%isolation%';
          2 +-----------------------+------------------+
          3 | Variable_name | Value |
          4 +-----------------------+------------------+
          5 | transaction_isolation | READ-UNCOMMITTED |
          6 +-----------------------+------------------+
          7 1 row in set (0.00 sec)

          在實(shí)際的業(yè)務(wù)場(chǎng)景中應(yīng)該都不允許臟讀出現(xiàn),既然這么評(píng)價(jià)不好為什么還會(huì)出現(xiàn)呢?但其實(shí)這個(gè)隔離級(jí)別下的數(shù)據(jù)庫(kù)并發(fā)性能是最好的。

          ?

          • Read Committed - 提交讀

          一個(gè)事務(wù)可以讀取另一個(gè)已提交的事務(wù),多次讀取會(huì)造成不一樣的結(jié)果。這種現(xiàn)象也被稱為不可重復(fù)讀。舉例說明:

          步驟事務(wù)1事務(wù)2
          1先設(shè)置隔離級(jí)別

          mysql> set @@session.transaction_isolation 
          = 'READ-COMMITTED';
          Query OK,
          0 rows affected (0.00 sec)

          mysql
          > select @@transaction_isolation;
          +-------------------------+
          | @@transaction_isolation |
          +-------------------------+
          | READ-COMMITTED |
          +-------------------------+
          1 row in set (0.00 sec)


          2開啟事務(wù)1,查詢t表記錄為空
          mysql> begin;
          Query OK,
          0 rows affected (0.00 sec)

          mysql
          > select * from t;
          Empty
          set (0.00 sec)

          3

          無需管隔離級(jí)別,只開啟事務(wù)2并插入記錄

          mysql> begin;
          Query OK,
          0 rows affected (0.00 sec)

          mysql
          > insert into t select 2, '2';
          Query OK,
          1 row affected (0.01 sec)
          Records:
          1 Duplicates: 0 Warnings: 0

          4

          繼續(xù)查詢表t依然顯示為空

          (沒有讀取到事務(wù)2未提交的數(shù)據(jù),所以不存在臟讀問題)

          mysql> select * from t;
          Empty
          set (0.00 sec)



          5

          ?提交事務(wù)2

          mysql> commit;
          6

          繼續(xù)查詢表t,此時(shí)能查詢事務(wù)2已提交的數(shù)據(jù)記錄(出現(xiàn)前后查詢不一致)

          mysql> select * from t;
          +------+------+
          | id | name |
          +------+------+
          | 2 | 2 |
          +------+------+


          總結(jié):在隔離級(jí)別中解決了臟讀問題,但存在不可重復(fù)讀的問題(事務(wù)中會(huì)讀取其他已提交事務(wù)中的數(shù)據(jù))?

          • Repeatable Read - 可重復(fù)讀

          該隔離級(jí)別是Innodb默認(rèn)的隔離級(jí)別:在同一個(gè)事務(wù)里select的結(jié)果是事務(wù)開始時(shí)間時(shí)間點(diǎn)的狀態(tài),解決了不可重復(fù)讀問題。

          但其中會(huì)出現(xiàn)幻讀現(xiàn)象:基于可重復(fù)讀的基礎(chǔ)上查詢結(jié)果是一樣的,但是當(dāng)對(duì)某些行進(jìn)行更新或者插入時(shí)卻會(huì)受到影響操作不了,就形成了幻讀。例如:

          步驟事務(wù)1事務(wù)2
          ?1

          設(shè)置隔離級(jí)別

          mysql> set @@session.transaction_isolation 
          = 'REPEATABLE-READ';

          mysql
          > select @@transaction_isolation;
          +-------------------------+
          | @@transaction_isolation |
          +-------------------------+
          | REPEATABLE-READ |
          +-------------------------+


          ?2

          ?開啟事務(wù)1,并查詢

          mysql> begin;
          Query OK,
          0 rows affected (0.00 sec)

          mysql
          > select * from t;
          +------+------+
          | id | name |
          +------+------+
          | 3 | 3 |
          +------+------+


          ?3

          ?無需管隔離級(jí)別,只開啟事務(wù)2并插入記錄

          mysql> begin;
          Query OK,
          0 rows affected (0.00 sec)

          mysql
          > insert into t select 4, '4';
          Query OK,
          1 row affected (0.01 sec)
          Records:
          1 Duplicates: 0 Warnings: 0

          4?繼續(xù)查詢表t依然只有一條記錄id=3

          (沒有讀取到事務(wù)2未提交的數(shù)據(jù),所以不存在臟讀問題)


          mysql> select * from t;
          +------+------+
          | id | name |
          +------+------+
          | 3 | 3 |
          +------+------+


          ?5
          ?

          將第二個(gè)窗口中的事務(wù)提交。


          mysql> commit;
          ?6繼續(xù)查詢表t依然只有一條記錄id=3

          (沒有讀取到事務(wù)2已提交的數(shù)據(jù),所以不存在不可重復(fù)讀問題)


          mysql> select * from t;
          +------+------+
          | id | name |
          +------+------+
          | 3 | 3 |
          +------+------+


          ?7?

          接著插入一條4的記錄,但提示插入不了,提示主鍵沖突問題。

          然而查詢卻沒有這條id=4記錄。這就是幻讀現(xiàn)象

          mysql> insert into t select 4, '4';
          ERROR
          1062 (23000): Duplicate entry '4' for key 'PRIMARY'
          mysql
          > select * from t;
          +----+------+
          | id | name |
          +----+------+
          | 3 | 3 |
          +----+------+
          1 row in set (0.00 sec)


          ?8??另一種幻讀現(xiàn)象:接著上面操作,不插入記錄只更新記錄,將name 更新成 '5'后,發(fā)現(xiàn)有兩行受影響

          ?

          mysql> update t set name = '5';
          Query OK,
          2 rows affected (0.00 sec)
          Rows matched:
          2 Changed: 2 Warnings: 0

          mysql
          > select * from t;
          +----+------+
          | id | name |
          +----+------+
          | 3 | 5 |
          | 4 | 5 |
          +----+------+


          總結(jié):在隔離級(jí)別中解決了臟讀問題、不可重復(fù)讀的問題,但會(huì)存在幻讀問題。

          但I(xiàn)nnodb引擎提供了間隙鎖:innodb-next-key-locks, 解決了幻讀問題。基于上面結(jié)果演示下:

          步驟事務(wù)1事務(wù)2
          9

          查詢時(shí)加上間隙鎖

          mysql> begin;
          mysql> select * from t where id  > 0 for update;
          +----+------+
          | id | name |
          +----+------+
          | 3 | 5 |
          | 4 | 5 |
          +----+------+

          ?


          ?10

          ?插入記錄為6的數(shù)據(jù)就會(huì)發(fā)現(xiàn)插入這條記錄獲取鎖超時(shí),自動(dòng)異常

          insert into t select 6, '6';
          ERROR
          1205 (HY000): Lock wait timeout exceeded; try restarting transaction

          ?

          這樣成功的避免了幻讀問題,阻止了其他事務(wù)可能影響到我當(dāng)前事務(wù)所涉及到的數(shù)據(jù)范圍。


          • Serializable - 可串行化

          在該隔離級(jí)別下事務(wù)都是串行順序執(zhí)行的,MySQL 數(shù)據(jù)庫(kù)的 InnoDB 引擎會(huì)給讀操作隱式加一把讀共享鎖,從而避免了臟讀、不可重讀復(fù)讀和幻讀問題。

          ?

          四、總結(jié)

            1、臟讀:在一個(gè)事務(wù)中會(huì)讀取到其未提交事務(wù)的數(shù)據(jù),此種現(xiàn)象也稱之為臟讀


            2、不可重復(fù)讀:一個(gè)事務(wù)可以讀取另一個(gè)已提交的事務(wù),多次讀取會(huì)造成不一樣的結(jié)果。這種現(xiàn)象也被稱為不可重復(fù)讀

            3、幻讀:基于可重復(fù)讀的基礎(chǔ)上查詢結(jié)果是一樣的,但是當(dāng)對(duì)某些行進(jìn)行更新或者插入時(shí)卻會(huì)受到影響操作不了,就形成了幻讀。

          隔離級(jí)別

          臟讀

          不可重復(fù)讀

          幻讀

          讀未提交(uncommitted read)

          可能出現(xiàn)

          可能出現(xiàn)

          可能出現(xiàn)

          讀提交(committed read)

          不會(huì)出現(xiàn)

          可能出現(xiàn)

          可能出現(xiàn)

          可重復(fù)讀(Repeatable Read)

          不會(huì)出現(xiàn)

          不會(huì)出現(xiàn)

          可能出現(xiàn)(加上間隙鎖就不會(huì))

          可串行化(Serializable)

          不會(huì)出現(xiàn)

          不會(huì)出現(xiàn)

          不會(huì)出現(xiàn)


          五、參考文獻(xiàn)

          《MySql 技術(shù)內(nèi)幕(Innodb)第二版》

          https://dev.mysql.com/doc/refman/8.0/en/innodb-transaction-isolation-levels.html






          粉絲福利:Java從入門到入土學(xué)習(xí)路線圖

          ??????

          ??長(zhǎng)按上方微信二維碼?2 秒


          感謝點(diǎn)贊支持下哈?

          瀏覽 51
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  含羞草国产一区二区 | 日韩精品一区二区亚洲AV观看 | 天天射天天射天天射 | 亚洲乱码国产乱码精品天美传媒 | www草逼 |