MYSQL事務(wù)-隔離級(jí)別

簡(jiǎn)書不維護(hù)了,歡迎關(guān)注我的知乎:波羅學(xué)的個(gè)人主頁(yè)

本篇文章的重點(diǎn)在于總結(jié)MYSQL事務(wù)。

事務(wù)是什么?

事務(wù)簡(jiǎn)言之就是一組SQL執(zhí)行要么全部成功,要么全部失敗。MYSQL的事務(wù)在存儲(chǔ)引擎層實(shí)現(xiàn)。

事務(wù)都有ACID特性:

  • 原子性(Atomicity):一個(gè)事務(wù)必須被視為一個(gè)不可分割的單元;
  • 一致性(Consistency):數(shù)據(jù)庫(kù)總是從一種狀態(tài)切換到另一種狀態(tài);
  • 隔離性(Isolation):通常來(lái)說(shuō),事務(wù)在提交前對(duì)于其他事務(wù)不可見;
  • 持久性(Durablity):一旦事務(wù)提交,所做修改永久保存數(shù)據(jù)庫(kù);

事務(wù)最常用的例子就是銀行轉(zhuǎn)賬。假設(shè)polo需給lynn轉(zhuǎn)賬1000元,如下步驟:

  • 確認(rèn)polo賬戶余額高于1000元;
  • 從polo的賬戶余額減去1000元;
  • 將lynn的賬戶余額增加1000元;

SQL語(yǔ)句如下:

mysql> BEGIN;
mysql> SELECT balance FROM bank_account WHERE uid=10001;
mysql> UPDATE bank_account SET balance=balance-1000 WHERE uid=10001;
mysql> UPDATE bank_account SET balance=balance+1000 WHERE uid=10002;
mysql> COMMIT;

注:mysql啟動(dòng)事務(wù)可使用BEGIN或者START TRANSACTION;

上述三個(gè)步驟執(zhí)行在一個(gè)事務(wù)中就能夠保證數(shù)據(jù)的完整性,要么全部成功,要么全部失敗。

MYSQL提供兩種事務(wù)型引擎:Innodb和NDBCluster。默認(rèn)采用自動(dòng)提交模式,執(zhí)行一條語(yǔ)句自動(dòng)COMMIT。通過(guò)AUTOCOMMIT變量可啟用或者禁用自動(dòng)提交模式:

mysql> SHOW VARIABLES LIKE "AUTOCOMMIT";
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+
1 row in set (0.00 sec)

mysql> SET AUTOCOMMIT=1

AUTOCOMMIT=1表示開啟默認(rèn)提交,0表示關(guān)閉默認(rèn)提交需要手動(dòng)提交。

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

事務(wù)隔離性的解釋:通常情況下,事務(wù)在提交之前對(duì)于其他事務(wù)不可見。

數(shù)據(jù)庫(kù)有四種隔離級(jí)別,當(dāng)然MYSQL也是如此。

本人理解,隔離級(jí)別就是決定一個(gè)事務(wù)的修改另一個(gè)事務(wù)什么情況下能看到。
書本解釋,每種級(jí)別都規(guī)定了一個(gè)事務(wù)中所做修改,哪些在事務(wù)內(nèi)和事務(wù)間是可見的。

區(qū)別在于是否存在事務(wù)內(nèi)可見性的規(guī)定。我在四個(gè)級(jí)別似乎沒(méi)有看到

下面開始說(shuō)明MYSQL的四種隔離級(jí)別,先準(zhǔn)備一張學(xué)生表:

mysql> CREATE TABLE `student` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `name` varchar(32) NOT NULL DEFAULT '',
 PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 |

只有id(主鍵自增)與name字段

  • READ UNCOMMITTED(未提交讀)
    事務(wù)中修改沒(méi)有提交對(duì)其他事務(wù)也是可見的,俗稱臟讀。非常不建議使用。

    實(shí)例演示
    客戶端A和B設(shè)置隔離級(jí)別為未提交讀

    mysql> SET SESSION TX_ISOLATION='READ-UNCOMMITTED';
    

    客戶端A與B開啟事務(wù)并查詢student

    mysql> BEGIN;
    mysql> SELECT * FROM student;
    Empty set (0.00 sec)
    

    客戶端A和B都是空數(shù)據(jù)

    客服端B插入一條新的數(shù)據(jù)

    mysql> INSERT INTO student(name) VALUES("polo");
    Query OK, 1 row affected (0.00 sec)
    

    此時(shí)事務(wù)未提交,客服端A查看student表

    $ SELECT * FROM student;
    mysql> SELECT * FROM student;
    +----+------+
    | id | name |
    +----+------+
    |  1 | polo |
    +----+------+
    1 row in set (0.00 sec)
    

    <font color=red>客戶端A看到B未提交的修改</font>

    客戶端B執(zhí)行回滾操作

    mysql> ROLLBACK
    

    成功之后,客戶端A查看student表

    mysql> SELECT * FROM student;
    Empty set (0.00 sec)
    

    <font color=red>客戶端A查看數(shù)據(jù)為空</font>

    以上可以看出未提交讀隔離級(jí)別的危險(xiǎn)性,對(duì)于一個(gè)沒(méi)有提交事務(wù)所做修改對(duì)另一個(gè)事務(wù)是可見狀態(tài),容易造成臟讀。非特殊情況不得使用此級(jí)別

  • READ COMMITTED(提交讀)
    多數(shù)數(shù)據(jù)庫(kù)系統(tǒng)默認(rèn)為此級(jí)別(MYSQL不是)。已提交讀級(jí)別即為一個(gè)事務(wù)只能已提交事務(wù)所做的修改,也就解決了未提交讀的問(wèn)題,即臟讀的問(wèn)題。

    實(shí)例演示
    客戶端A和B設(shè)置隔離級(jí)別為已提交讀

    mysql> SET SESSION TX_ISOLATION='READ-COMMITTED';
    

    客戶端A與B開啟事務(wù)并查詢student

    mysql> BEGIN;
    mysql> SELECT * FROM student;
    Empty set (0.00 sec)
    

    客戶端A和B都為空
    客服端B插入一條新的數(shù)據(jù),不提交

    mysql> INSERT INTO student (name) VALUES('polo');
    

    客戶端A查看student

    mysql> SELECT * FROM student;
    Empty set (0.00 sec)
    

    <font color=red>注意這里與上面不同了,在客戶端B沒(méi)有提交事務(wù)情況下無(wú)數(shù)據(jù)</font>
    下面客戶端B提交事務(wù)

    mysql> COMMIT;
    

    客戶端A再次查看student表。

    mysql> SELECT * FROM student;
    +----+------+
    | id | name |
    +----+------+
    |  1 | polo |
    +----+------+
    1 row in set (0.00 sec)
    

    成功讀取到客戶

    從上面的示例可以看出,提交讀沒(méi)有了未提交讀的問(wèn)題,但我們可以看到在客戶端A的一個(gè)事務(wù)中執(zhí)行兩次同樣的SELECT語(yǔ)句得到不同結(jié)果,因此已提交讀又被稱為不可重復(fù)讀。同樣篩選條件可能得到不同的結(jié)果。

  • REPEATABLE READ(可重復(fù)讀)
    如其名也,解決已提交讀不可重復(fù)讀取的問(wèn)題。

    示例演示
    客戶端A和B設(shè)置隔離級(jí)別為可重復(fù)讀

    mysql> SET SESSION tx_isolation='REPEATABLE-READ'
    

    客戶端A與B開啟事務(wù)并查看

    mysql> BEGIN;
    mysql> SELECT * FROM student;
    +----+------+
    | id | name |
    +----+------+
    |  1 | polo |
    +----+------+
    1 rows in set (0.00 sec)
    

    客服端B更新polo為adam,并提交事務(wù)

    mysql> UPDATE student SET name='adam' WHERE id=1;
    mysql> COMMIT
    

    客戶端A查看student表

    mysql> SELECT * FROM student;
    +----+------+
    | id | name |
    +----+------+
    |  1 | polo |
    +----+------+
    1 rows in set (0.00 sec)
    

    <font color=red>注意客戶端A查看數(shù)據(jù)未變,沒(méi)有不可重復(fù)讀問(wèn)題</font>

    客戶端A提交事務(wù),并查看student表

    mysql> COMMIT;
    mysql> SELECT * FROM student;
    +----+------+
    | id | name |
    +----+------+
    |  1 | polo |
    +----+------+
    1 rows in set (0.00 sec)
    

    上面實(shí)例可知,可重復(fù)讀兩次讀取內(nèi)容一樣。數(shù)據(jù)庫(kù)這級(jí)別并沒(méi)有解決幻讀的問(wèn)題。但是MYSQL在可重復(fù)讀基礎(chǔ)上增加了MVCC機(jī)制解決了此問(wèn)題,實(shí)例無(wú)法演示幻讀效果。

    那什么是幻讀?首先,可重復(fù)讀鎖定范圍為當(dāng)前查詢到的內(nèi)容,如執(zhí)行

    mysql> SELECT * FROM student WHERE id>=1
    

    鎖定的即id>=1查到的行,為行級(jí)鎖。如另一事務(wù)執(zhí)行并默認(rèn)提交以下語(yǔ)句

    mysql> INSERT INTO student (name) VALUES ('stephen');
    

    新增的這行并沒(méi)有被鎖定,此時(shí)讀取student

    mysql> SELECT * FROM student WHERE id>=1;
    +----+---------+
    | id | name    |
    +----+---------+
    |  1 | polo    |
    |  2 | stephen |
    +----+---------+
    2 rows in set (0.00 sec)
    

    便出現(xiàn)了幻讀

    除了使用MYSQL的MVCC機(jī)制,還可以使用可串行化隔離級(jí)別解決此問(wèn)題。

  • SEAIALIZABLE(可串行化)
    可串行化是最高隔離級(jí)別,強(qiáng)制事務(wù)串行執(zhí)行。執(zhí)行串行了也就解決了一切的問(wèn)題,這個(gè)級(jí)別只有在對(duì)數(shù)據(jù)一致性要求非常嚴(yán)格且沒(méi)用并發(fā)的情況下使用

    實(shí)例演示
    客戶端A和B設(shè)置隔離級(jí)別為可串行化

    mysql> SET SESSION tx_isolation='SERIALIZABLE';
    

    客戶端A執(zhí)行查詢

    mysql> SELECT * FROM student WHERE id<4;
    +----+---------+
    | id | name    |
    +----+---------+
    |  1 | polo    |
    |  2 | stephen |
    +----+---------+
    2 rows in set (0.00 sec)
    

    客戶端B執(zhí)行新增

    mysql> INSERT INTO student (name) VALUES('yunteng');
    

    好的!效果出現(xiàn)了,此時(shí)我們會(huì)發(fā)現(xiàn)INSERT語(yǔ)句被阻塞執(zhí)行,原因就是A執(zhí)行了查詢表student同時(shí)滿足id<4,已被鎖定。如果查詢表student條件為id<3,則新增語(yǔ)句可正常執(zhí)行。

隔離級(jí)別對(duì)照?qǐng)D

隔離級(jí)別 臟讀 不可重復(fù)讀 幻讀 加鎖讀
未提交讀
提交讀
可重復(fù)讀
未提交讀

好了,關(guān)于事務(wù)的隔離級(jí)別就說(shuō)這么多,希望自己的理解沒(méi)有錯(cuò)誤。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,885評(píng)論 6 541
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,312評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 177,993評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,667評(píng)論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,410評(píng)論 6 411
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,778評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,775評(píng)論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,955評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,521評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,266評(píng)論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,468評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,998評(píng)論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,696評(píng)論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,095評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,385評(píng)論 1 294
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,193評(píng)論 3 398
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,431評(píng)論 2 378

推薦閱讀更多精彩內(nèi)容