MYSQL事務-隔離級別

簡書不維護了,歡迎關注我的知乎:波羅學的個人主頁

本篇文章的重點在于總結MYSQL事務横媚。

事務是什么?

事務簡言之就是一組SQL執(zhí)行要么全部成功底循,要么全部失敗。MYSQL的事務在存儲引擎層實現(xiàn)廊驼。

事務都有ACID特性:

  • 原子性(Atomicity):一個事務必須被視為一個不可分割的單元;
  • 一致性(Consistency):數(shù)據庫總是從一種狀態(tài)切換到另一種狀態(tài)惋砂;
  • 隔離性(Isolation):通常來說妒挎,事務在提交前對于其他事務不可見;
  • 持久性(Durablity):一旦事務提交西饵,所做修改永久保存數(shù)據庫酝掩;

事務最常用的例子就是銀行轉賬。假設polo需給lynn轉賬1000元眷柔,如下步驟:

  • 確認polo賬戶余額高于1000元期虾;
  • 從polo的賬戶余額減去1000元原朝;
  • 將lynn的賬戶余額增加1000元;

SQL語句如下:

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啟動事務可使用BEGIN或者START TRANSACTION镶苞;

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

MYSQL提供兩種事務型引擎:Innodb和NDBCluster。默認采用自動提交模式谢澈,執(zhí)行一條語句自動COMMIT煌贴。通過AUTOCOMMIT變量可啟用或者禁用自動提交模式:

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

mysql> SET AUTOCOMMIT=1

AUTOCOMMIT=1表示開啟默認提交,0表示關閉默認提交需要手動提交锥忿。

事務隔離級別

事務隔離性的解釋:通常情況下牛郑,事務在提交之前對于其他事務不可見。

數(shù)據庫有四種隔離級別敬鬓,當然MYSQL也是如此淹朋。

本人理解,隔離級別就是決定一個事務的修改另一個事務什么情況下能看到钉答。
書本解釋础芍,每種級別都規(guī)定了一個事務中所做修改,哪些在事務內和事務間是可見的数尿。

區(qū)別在于是否存在事務內可見性的規(guī)定仑性。我在四個級別似乎沒有看到

下面開始說明MYSQL的四種隔離級別,先準備一張學生表:

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(未提交讀)
    事務中修改沒有提交對其他事務也是可見的右蹦,俗稱臟讀诊杆。非常不建議使用。

    實例演示
    客戶端A和B設置隔離級別為未提交讀

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

    客戶端A與B開啟事務并查詢student

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

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

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

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

    此時事務未提交晨汹,客服端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ù)據為空</font>

    以上可以看出未提交讀隔離級別的危險性贷盲,對于一個沒有提交事務所做修改對另一個事務是可見狀態(tài)淘这,容易造成臟讀。非特殊情況不得使用此級別

  • READ COMMITTED(提交讀)
    多數(shù)數(shù)據庫系統(tǒng)默認為此級別(MYSQL不是)巩剖。已提交讀級別即為一個事務只能已提交事務所做的修改慨灭,也就解決了未提交讀的問題,即臟讀的問題球及。

    實例演示
    客戶端A和B設置隔離級別為已提交讀

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

    客戶端A與B開啟事務并查詢student

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

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

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

    客戶端A查看student

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

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

    mysql> COMMIT;
    

    客戶端A再次查看student表吃引。

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

    成功讀取到客戶

    從上面的示例可以看出筹陵,提交讀沒有了未提交讀的問題刽锤,但我們可以看到在客戶端A的一個事務中執(zhí)行兩次同樣的SELECT語句得到不同結果,因此已提交讀又被稱為不可重復讀朦佩。同樣篩選條件可能得到不同的結果并思。

  • REPEATABLE READ(可重復讀)
    如其名也,解決已提交讀不可重復讀取的問題语稠。

    示例演示
    客戶端A和B設置隔離級別為可重復讀

    mysql> SET SESSION tx_isolation='REPEATABLE-READ'
    

    客戶端A與B開啟事務并查看

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

    客服端B更新polo為adam宋彼,并提交事務

    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ù)據未變,沒有不可重復讀問題</font>

    客戶端A提交事務仙畦,并查看student表

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

    上面實例可知输涕,可重復讀兩次讀取內容一樣。數(shù)據庫這級別并沒有解決幻讀的問題慨畸。但是MYSQL在可重復讀基礎上增加了MVCC機制解決了此問題莱坎,實例無法演示幻讀效果。

    那什么是幻讀寸士?首先檐什,可重復讀鎖定范圍為當前查詢到的內容,如執(zhí)行

    mysql> SELECT * FROM student WHERE id>=1
    

    鎖定的即id>=1查到的行弱卡,為行級鎖乃正。如另一事務執(zhí)行并默認提交以下語句

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

    新增的這行并沒有被鎖定,此時讀取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機制婶博,還可以使用可串行化隔離級別解決此問題烫葬。

  • SEAIALIZABLE(可串行化)
    可串行化是最高隔離級別,強制事務串行執(zhí)行凡蜻。執(zhí)行串行了也就解決了一切的問題搭综,這個級別只有在對數(shù)據一致性要求非常嚴格且沒用并發(fā)的情況下使用

    實例演示
    客戶端A和B設置隔離級別為可串行化

    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)了划栓,此時我們會發(fā)現(xiàn)INSERT語句被阻塞執(zhí)行兑巾,原因就是A執(zhí)行了查詢表student同時滿足id<4,已被鎖定忠荞。如果查詢表student條件為id<3蒋歌,則新增語句可正常執(zhí)行。

隔離級別對照圖

隔離級別 臟讀 不可重復讀 幻讀 加鎖讀
未提交讀
提交讀
可重復讀
未提交讀

好了委煤,關于事務的隔離級別就說這么多堂油,希望自己的理解沒有錯誤。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末碧绞,一起剝皮案震驚了整個濱河市府框,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌讥邻,老刑警劉巖迫靖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件院峡,死亡現(xiàn)場離奇詭異,居然都是意外死亡系宜,警方通過查閱死者的電腦和手機照激,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來盹牧,“玉大人俩垃,你說我怎么就攤上這事√ⅲ” “怎么了口柳?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長踩寇。 經常有香客問我啄清,道長六水,這世上最難降的妖魔是什么俺孙? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮掷贾,結果婚禮上睛榄,老公的妹妹穿的比我還像新娘。我一直安慰自己想帅,他們只是感情好场靴,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著港准,像睡著了一般旨剥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上浅缸,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天轨帜,我揣著相機與錄音,去河邊找鬼衩椒。 笑死蚌父,一個胖子當著我的面吹牛,可吹牛的內容都是我干的毛萌。 我是一名探鬼主播苟弛,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼阁将!你這毒婦竟也來了膏秫?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤做盅,失蹤者是張志新(化名)和其女友劉穎荔睹,沒想到半個月后狸演,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體邢疙,經...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡炮障,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了略荡。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吨拗。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡满哪,死狀恐怖,靈堂內的尸體忽然破棺而出劝篷,到底是詐尸還是另有隱情哨鸭,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布娇妓,位于F島的核電站像鸡,受9級特大地震影響,放射性物質發(fā)生泄漏哈恰。R本人自食惡果不足惜只估,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望着绷。 院中可真熱鬧蛔钙,春花似錦、人聲如沸荠医。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽彬向。三九已至兼贡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間娃胆,已是汗流浹背遍希。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留缕棵,地道東北人孵班。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像招驴,于是被迫代替她去往敵國和親篙程。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內容