1. 程式人生 > 實用技巧 >MySQL的四種隔離級別

MySQL的四種隔離級別

宣告:首先這邊博文,是針對網上看到一篇博文的完善與補充,因為那篇博文有問題,在第三個實驗中有錯誤,讓人看不明白,有錯誤,所以我這邊完善與補充那篇博文,如果以下正確的地方,我就複製了。

通過本次的學習,終於搞明白了事務的隔離級別以及髒讀幻讀等出現的原因,原文地址:https://www.cnblogs.com/zyzblogs/p/11375381.html

  • 首先要明白什麼是事務?
    • 事務是程式中一系列嚴密的操作,所有的操作必須完成,否則在所有的操作中所做的所有的更改都會被撤銷。也就是事務的原子性,一個事務中的一系列的操作要麼全部成功,要麼全部不做
    • 事務的結束有兩種,當事務中所有的步驟全部成功執行的時候,事務提交。如果其中一個步驟失敗,將會發生回滾操作,撤銷到事務開始之前的所有的操作。
  • 事務的ACID
    • 事務具有四個特徵
      • 原子性
        • 事務是資料庫的邏輯工作單位,事務中包含多個操作,要麼都走,要麼都不做
      • 隔離性
        • 事務彼此之間是不能互相干擾的,即一個事務的操作對該資料庫的其他事務操作是隔離的,併發執行的各個事務時間互補干擾
      • 持續性
        • 事務一旦提交,其變更是永久性的,
      • 一致性
        • 事務執行的結果必須滿足從一個狀態變到另一個狀態,因此當資料庫只包含成功事務提交的結果時,就說資料庫處於一致性的狀態。如果資料庫系統在執行時發生系統故障,有些未完成的事務被迫中止,而有一部分修改已經寫入資料庫,這個時候資料庫就處於一種不正確的狀態。其實以上三個條件最終都是為了保持資料庫資料的一致性服務的
  • MySQL的四種隔離級別
    • SQL標準定義了四種隔離級別,用來限定事務內外的哪些改變是可見的,哪些是不可見的
      • 讀取未提交的資料【Read Uncommitted】
        • 在改隔離級別,所有的事務都可以看到其他事務沒有提交的執行結果。很少用於實際應用。效能也不必其他的級別好多少
      • 讀取提交的內容【Read Committed】
        • 該隔離級別是大多數資料庫的預設的隔離級別(不是MySQL預設的)。它滿足了隔離的簡單定義:一個事務只能看到其他的已經提交的事務所做的改變。這種隔離級別也支援不可重複讀,即同一個select可能得到不同的結果
      • 可重讀【Repeatable Read】
        • 這是MySQL預設的隔離級別,它確保同一個事務在併發讀取資料時,會看到同樣的資料行。不過理論上會導致另外一個問題,幻讀。幻讀:相同的條件查詢一些資料,然後其他事務新增或者是刪除了該條件的資料,然後導致讀取的結果不一樣多。InnoDB和Falcon儲存引擎通過多版本控制(MVCC)機制解決了該問題
      • 可序列化【serializable】
        • 這是事務的最高隔離級別,它通過強制事務排序,使之不可能相互衝突,從而解決了幻讀的問題。它在每個讀的資料行上面加上共享鎖,。但是可能會導致超時和鎖競爭
      • 這四種隔離級別採用不同的鎖型別來實現
        • 髒讀
          • 讀取了前一個事務未提交的或者是回滾的資料
        • 不可重複度
          • 同樣的select查詢,但是結果不同,過程中有事務更新了原有的資料
        • 幻讀
          • 兩次查詢的結果數量不一樣,過程中有事務新增或者是刪除資料
隔離級別 髒讀 不可重複度 幻讀
讀取未提交的
讀取提交的 不會
可重讀 不會 不會
可序列化 不會 不會 不會

建立sql語句:

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for test
-- ----------------------------
DROP TABLE IF EXISTS `test`;
CREATE TABLE `test`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `num` int(11) NOT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of test
-- ----------------------------
INSERT INTO `test` VALUES (1, 1);
INSERT INTO `test` VALUES (2, 2);
INSERT INTO `test` VALUES (3, 3);
INSERT INTO `test` VALUES (4, 4);

SET FOREIGN_KEY_CHECKS = 1;
檢視資料庫的隔離級別
show variables like '%isolation%'
設定資料庫的隔離級別
set session transaction isolation level Read Uncommitted;
設定資料庫的隔離級別為:Read Uncommitted

實驗一:讀取未提交-Read Uncommitted

前置條件:將資料庫的隔離級別設定為read uncomitted; set session transaction isolation level Read Uncommitted;

第一步:A開啟事務:start tracsaction;

第二步:A查詢資料:select *from test;

第三步:B開啟事務:start transaction;

第四步:B查詢資料:select * from test;

第五步:B更新資料:update test set num=10 where id=1;B沒有提交事務

第六步:A讀取資料—-A讀取到了B未提交的資料(當前資料庫的隔離級別是:Read Uncommitted)

第七步:B回滾資料:rollback;

第八步:B查詢資料:select *from test;

第九步:A查詢數:select * from test;

結論:事務B更新了資料,但是沒有提交,事務A讀取到的是B未提交的記錄。因為造成髒讀。Read Uncommitted是最低的隔離級別。讀取未提交的 A這邊提交了,但是還沒提交事務,但是B在另外一邊卻讀取到了資料是A提交但是還沒提交的事務.

實驗二:讀取已提交-Read Committed

前置條件:將資料庫的隔離級別設定為:Read Committed;
set session transaction isolaction level Read Committed;

第一步:A開始事務:start transaction;

第二步:A查詢資料:select *from test;

第三步:B開啟事務:start transaction;

第四步:B查詢資料:select *from test;

第五步:B更新資料:update test set num=10 where id=1;

第六步:A查詢資料:select * from test;

第七步:B提交資料:commit;

第八步:A查詢資料:select * from test;

結論:ReadCommitted讀已提交的隔離級別解決了髒讀的問題,但是出現了不可重複讀的問題,即事務A在兩次查詢的結果不一致,因為在兩次查詢之間事務B更新了一條資料。 讀已提交的只允許讀取已經提交的記錄 ,但是不要求可重複讀。 讀取提交的 A這邊這邊提交了資料,並且提交事務了,B這邊取得了A提交的資料並且與提交了事務的詩句

實驗三:可重讀度-Repeatable Read

前置條件:將資料庫的級別設定為可重複度
set session transaction isolation level repeatable read;

第一、二步:A開始事務:start transaction;並且查詢A的資料:select * from test;

第三步:B開啟事務:start transaction;

第四步:B查詢資料:select * from test;

第五步:B更新資料:update test set num=10 where id=1;

第六步:B查詢資料:select * from test;

第七步:提交事務。

第八步:查詢的A的資料。

第九步:在B視窗中在此插入一條資料,並且查詢。

第十步:在此查詢A的資料。

最後A也提交事務,此時發現A查詢的資料已經和B查詢的結果一致了; 結論:Repeatable Read隔離級別只允許讀取已經提交的事務的記錄。 可重複度 A這邊不管你提交什麼資料或者插入的資料,在B這邊取得的資料都是不變了,都是跟以前的開啟事務之前那一次的資料一樣的.

實驗四:客序列化-Serializable

​前置條件:將資料庫的隔離級別設定為可序列化

第一步:A開始事務並查詢資料

第二步:B開啟事務並insert資料,發現只能等待,並不能執行下去

第三步:A提交事務

第四步:B插入資料 結論:serializable完全鎖定欄位,若一個事務來操作同一份資料,那麼就必須等待,直到前一個事務完成並解除鎖為止。是完整的隔離級別,會鎖住對應的資料表,因為會導致效率問題。 可序列化,就是一個個按照佇列來,然後相當於開啟了事務後,就直接上鎖了,將表鎖起來了,其他都都不能讀與寫,這種是最安全的,但是效率也是最低的. zz:https://www.321dz.com/2047.html