1. 程式人生 > >MySQL InnoDB事務隔離級別髒讀、可重複讀、幻讀

MySQL InnoDB事務隔離級別髒讀、可重複讀、幻讀

望通過本文,可以加深讀者對ySQL InnoDB的四個事務隔離級別,以及髒讀、不重複讀、幻讀的理解。

有四級,預設是可重複讀REPEATABLE READ)。

·        未提交讀(READUNCOMMITTED)。另一個事務修改了資料,但尚未提交,而本事務中的SELECT會讀到這些未被提交的資料(髒讀)。

·        提交讀(READCOMMITTED)。本事務讀取到的是最新的資料(其他事務提交後的)。問題是,在同一個事務裡,前後兩次相同的SELECT會讀到不同的結果(不重複讀)。

·        可重複讀(REPEATABLEREAD

)。在同一個事務裡,SELECT的結果是事務開始時時間點的狀態,因此,同樣的SELECT操作讀到的結果會是一致的。但是,會有幻讀現象(稍後解釋)。

·        序列化(SERIALIZABLE)。讀操作會隱式獲取共享鎖,可以保證不同事務間的互斥。

四個級別逐漸增強,每個級別解決一個問題。

·        髒讀,最容易理解。另一個事務修改了資料,但尚未提交,而本事務中的SELECT會讀到這些未被提交的資料。

·        不重複讀。解決了髒讀後,會遇到,同一個事務執行過程中,另外一個事務提交了新資料,因此本事務先後兩次讀到的資料結果會不一致。

·        

幻讀。解決了不重複讀,保證了同一個事務裡,查詢的結果都是事務開始時的狀態(一致性)。但是,如果另一個事務同時提交了新資料,本事務再更新時,就會驚奇的發現了這些新資料,貌似之前讀到的資料是鬼影一樣的幻覺。

MySQL InnoDB事務隔離級別可設定為global和session級別。

事務隔離級別檢視

檢視當前session的事務隔離級別:

  1. mysql> show variables like'%tx_isolation%';  
  2. +---------------+--------------+
  3. | Variable_name | Value        |  
  4. +---------------+--------------+
  5. | tx_isolation  | SERIALIZABLE |  
  6. +---------------+--------------+
設定事務隔離級別:

設定global事務隔離級別:

 set global isolation level read committed;

注意一點的設定global並不會對當前session生效。

設定session事務隔離級別sql指令碼:

  1. set session transactionisolationlevelreaduncommitted;        
  2. set session transactionisolationlevelreadcommitted;        
  3. set session transactionisolationlevelREPEATABLEREAD;     
  4. set session transactionisolationlevelSERIALIZABLE;  

上面的文字,讀起來並不是那麼容易讓人理解,以下用幾個實驗對InnoDB的四個事務隔離級別做詳細的解釋,希望通過實驗來加深大家對InnoDB的事務隔離級別理解。

  1. CREATETABLE `t` (  
  2.     `a` INT (11) NOTNULLPRIMARYKEY
  3. ) ENGINE = INNODB DEFAULT CHARSET = UTF8;  
  4. INSERTINTO t (a) VALUES (1),(2),(3);  

實驗一:解釋髒讀、可重複讀問題

更新事務

事務A READ-UNCOMMITTED

事務B READ-COMMITTED,

事務C-1 REPEATABLE-READ

事務C-2 REPEATABLE-READ

事務D SERIALIZABLE

set autocommit =0;

start transaction ;

start transaction;

insert into t(a)values(4);

select * from t;

1,2,3,4(髒讀:讀取到了未提交的事務中的資料)

select * from t;

1,2,3(解決髒讀)

select * from t;

1,2,3

select * from t;

1,2,3

select * from t;

1,2,3

commit;

select * from t:

1,2,3,4

select * from t:

1,2,3,4

select * from t:

1,2,3,4 (與上面的不在一個事務中,所以讀到為事務提交後最新的,所以可讀到4)

select * from t:

1,2,3(重複讀:由於與上面的在一個事務中,所以只讀到事務開始事務的資料,也就是重複讀)

select * from t:

1,2,3,4

commit(提交事務,下面的就是一個新的事務,所以可以讀到事務提交以後的最新資料)

select * from t:

1,2,3,4

READ-UNCOMMITTED 會產生髒讀,基本很少適用於實際場景,所以基本不使用。

實驗二:測試READ-COMMITTED與REPEATABLE-READ

事務A

事務B READ-COMMITTED

事務C REPEATABLE-READ

set autocommit =0;

start transaction ;

start transaction;

start transaction;

insert into t(a)values(4);

select * from t;

1,2,3

select * from t;

1,2,3

commit;

select * from t:

1,2,3,4

select * from t:

1,2,3(重複讀:由於與上面的在一個事務中,所以只讀到事務開始事務的資料,也就是重複讀)

commit(提交事務,下面的就是一個新的事務,所以可以讀到事務提交以後的最新資料)

select * from t:

1,2,3,4

REPEATABLE-READ可以確保一個事務中讀取的資料是可重複的,也就是相同的讀取(第一次讀取以後,即使其他事務已經提交新的資料,同一個事務中再次select也並不會被讀取)。

READ-COMMITTED只是確保讀取最新事務已經提交的資料。

當然資料的可見性都是對不同事務來說的,同一個事務,都是可以讀到此事務中最新資料的。

  1. start transaction;  
  2. insertinto t(a) values (4);  
  3. select  * from t;  
  4. 1,2,3,4;  
  5. insertinto t(a) values (5);  
  6. select  * from t;  
  7. 1,2,3,4,5;  


 實驗三:測試SERIALIZABLE事務對其他的影響

事務A SERIALIZABLE

事務B READ-UNCOMMITTED

事務C READ-COMMITTED,

事務D REPEATABLE-READ

事務E SERIALIZABLE

set autocommit =0;

start transaction ;

start transaction;

select a from t union all select sleep(1000) from dual;

insert into t(a)values(5);

insert into t(a)values(5);

insert into t(a)values(5);

insert into t(a)values(5);

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

SERIALIZABLE 序列化執行,導致所有其他事務不得不等待事務A結束才行可以執行,這裡特意使用了sleep函式,直接導致事務B,C,D,E等待事務A持有釋放的鎖。由於我sleep了1000秒,而innodb_lock_wait_timeout為120s。所以120s到了就報錯HY000錯誤。

SERIALIZABLE是相當嚴格的序列化執行模式,不管是讀還是寫,都會影響其他讀取相同的表的事務。是嚴格的表級讀寫排他鎖。也就失去了innodb引擎的優點。實際應用很少。

實驗四:幻讀

一些文章寫到InnoDB的可重複讀避免了幻讀phantom read),這個說法並不準確。

做個試驗:(以下所有試驗要注意儲存引擎和隔離級別)

  1. mysql>show createtable t_bitfly\G;  
  2. CREATETABLE `t_bitfly` (  
  3. `id` bigint(20) NOTNULLdefault'0',  
  4. `value` varchar(32) defaultNULL,  
  5. PRIMARYKEY (`id`)  
  6. ) ENGINE=InnoDB DEFAULT CHARSET=gbk  
  7. mysql>select @@global.tx_isolation, @@tx_isolation;  
  8. +-----------------------+-----------------+
  9. | @@global.tx_isolation | @@tx_isolation  |  
  10. +-----------------------+-----------------+
  11. REPEATABLE-READ       | REPEATABLE-READ |  
  12. +-----------------------+-----------------+

試驗4-1

  1. SessionA                                                                            Session B  
  2. START TRANSACTION;                                                                  START TRANSACTION;  
  3. SELECT * FROM t_bitfly;  
  4. empty set
  5.                                                                                     INSERTINTO t_bitfly VALUES (1, 'a');  
  6. SELECT * FROM t_bitfly;  
  7. empty set
  8.                                                                                     COMMIT;  
  9. SELECT * FROM t_bitfly;  
  10. empty set
  11. INSERTINTO t_bitfly VALUES (1, 'a');  
  12. ERROR 1062 (23000):  
  13. Duplicate entry '1'forkey 1  



v (shit, 剛剛明明告訴我沒有這條記錄的)

如此就出現了幻讀,以為表裡沒有資料,其實資料已經存在了,傻乎乎的提交後,才發現數據衝突了。

試驗4-2

  1. SessionA                                                                         Session B  
  2. START TRANSACTION;                                                               START 

    相關推薦

    MySQL InnoDB事務隔離級別重複

    望通過本文,可以加深讀者對ySQL InnoDB的四個事務隔離級別,以及髒讀、不重複讀、幻讀的理解。 有四級,預設是“可重複讀”(REPEATABLE READ)。 ·        未提交讀(READUNCOMMITTED)。另一個事務修改了資料

    mysql-Innodb事務隔離級別-repeatable read詳解

    經驗總結: python使用MySQLdb資料庫後,如使用多執行緒,每個執行緒建立一個db連結,然後再各自建立一個遊標cursor,其中第一個執行緒讀一個表中資料為空,第二個寫入該表一條資料並提交,第一個執行緒再讀該表資料將仍然無法讀出。和多資料庫的事務級別應該有關係;還可

    資料庫事務隔離級別-- 不可重複(清晰解釋)

    一、資料庫事務隔離級別 資料庫事務的隔離級別有4個,由低到高依次為Read uncommitted 、Read committed 、Repeatable read 、Serializable ,這四個級別可以逐個解決髒讀 、不可重複讀 、幻讀 這幾類問題。 √: 可能出

    資料庫事務隔離級別-- 不可重複

    一 、資料庫事務隔離級別 從高到低: 序列化    serilizable      消耗資源比較嚴重 重複讀    repeatable read    Oracle 預設的事務隔離級別 讀提交    read committed    Mysql 預設的隔離級別

    MySQL預設事務隔離級別(RR)到InnoDB非鎖定一致性

    說到資料庫的隔離級別,我想大家都能說出一二,但是很多時候都是從網上看來的,很多都點到為止不夠詳細,並且沒有經過實踐的檢驗,所以有時候我們會發現有些東西並沒有按照我們預期的來工作,這裡就是一個例子。MySQL目前流行的版本預設的事務隔離級別一般是可重複讀,一般我們理解在這個隔離

    InnoDB 事務隔離級別Mysql篇)

    前言: Mysql支援MyISAM和InnoDB兩種儲存引擎,區別在此就不詳細說明。此篇是講述事務,所以切記自己的table是InnDB。此處大坑! 在Mysql InnoDB 中,事務主要有四種隔離級別 Read unco

    一文MySQL事務隔離級別及MVCC機制

    回顧前文: [一文學會MySQL的explain工具](https://www.cnblogs.com/itwild/p/13424113.html) [一文讀懂MySQL的索引結構及查詢優化](https://www.cnblogs.com/itwild/p/13703259.html)

    mysql事務隔離級別

    too con jpg 級別 tran 開啟 數據行 修改 ges 原文地址:http://www.cnblogs.com/snsdzjlz320/p/5761387.html [Mysql]——通過例子理解事務的4種隔離級別 SQL標準定義了4種隔離級別,包括了一

    mysql 不同事務隔離級別

    結果 讀取 般的 lec 不同的 新增 比較 一次 基礎 repeatable read 在同一事務中,同一查詢多次進行時候,由於其他插入操作(insert)的事務提交,導致每次返回不同的結果集。 標準的repeatable read是允許幻讀的,因為這一級別只在讀取過的紀

    談談MySQL事務隔離級別

    提交 執行過程 操作 dnf 情況 以及 讀取 int 並且 這篇文章能夠闡述清楚跟數據庫相關的四個概念:事務、數據庫讀現象、隔離級別、鎖機制   一、事務 先來看下百度百科對數據庫事務的定義:   作為單個邏輯單元執行一系列操作,要麽完全執行,要麽完全不執行。事務處理可以

    MySQL實戰 | 03 - 誰動了我的資料:淺析MySQL事務隔離級別

    原文連結:這一次,帶你搞清楚MySQL的事務隔離級別! 使用過關係型資料庫的,應該都事務的概念有所瞭解,知道事務有 ACID 四個基本屬性:原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)和永續性(Durability),今天我們主要來理解一下事務的隔離性。

    遇到mysql資料庫事務隔離級別相關的小坑

    幾乎所有軟體工程師都知道,mysql有4種事務隔離級別,但是實際開發過程中可能有時候忽略這個小細節,有時候可能是本來就沒有考慮過,有時候也可能是其他的原因,比如我這次踩到的小坑。 事情還原: 1、需求一:是新建一個商戶,但是客戶要求在建立商戶的時候要預設給他們開

    MySQL資料庫事務隔離級別(Transaction Isolation Level)

    今天在學習JDBC的時候看到了關於MySql的事務的隔離級別的問題,感覺內容挺高階的,所以記錄一篇文章,以備後面使用。 資料庫隔離級別有四種,應用《高效能mysql》一書中的說明: 然後說說修改事務隔離級別的方法: 1.全域性修改,修改mysql.in

    MySQL---InnoDB引擎隔離級別詳解

    #首先修改隔離級別 set tx_isolation='read-committed'; select @@tx_isolation; +----------------+ | @@tx_isolation | +----------------+ | READ-COMMITTED | +--------

    innodb事務隔離級別

    事務隔離級別 SQL標準定義了4類隔離級別,包括了一些具體規則,用來限定事務內外的哪些改變是可見的,哪些是不可見的。低級別的隔離級一般支援更高的併發處理,並擁有更低的系統開銷。 Read Uncommitted(讀取未提交內容)       在該隔離級別,所有事務都可以看到

    Mysql事務隔離級別與binlog_format的一點理解

        之前幾年的軟體開發,總是離不開Oracle,涉及的各大專案中使用的資料庫也大多為Oracle,偶爾遇到Mysql也是簡單的使用,一直覺得Mysql很小型也很簡單,對其的理解也處於皮毛階段,最近遇到了一些Mysql的問題,對其中的事務隔離級別,以及binlog_for

    MySQL事務隔離級別及ACID

    注:begin或start transaction並不是一個事務的起點,而是在執行它們之後的第一個操作InnoDB表的語句,事務才真正開始。start transaction with consistent snapshot命令可以馬上啟動一個事務。 1、隔離級別 1.1、基本概念 讀未提交 當前事務能讀取

    ,不可重複度,

    【1】髒讀(讀取未提交資料)         事物A讀取事物B尚未提交的資料,此時事物B發生回滾,那麼事物A讀到的資料就是髒資料,俗稱髒讀         這類情況長髮生在轉賬和取款操作中:                        【2】不可重複讀(前後多

    和不可重複 + 事務隔離級別

    1. 髒讀 :髒讀就是指當一個事務正在訪問資料,並且對資料進行了修改,而這種修改還沒有提交到資料庫中,這時,另外一個事務也訪問這個資料,然後使用了這個資料。  e.g.         1.Mary的原工資為1000, 財務人員將Mary的工資改為了8000(但未提交事務

    資料庫事務隔離級別不可重複

    資料庫事務的隔離級別有4個,由低到高依次為Read uncommitted 、Read committed 、Repeatable read 、Serializable  ,後面三個可以逐個解決髒讀 、不可重複讀 、幻讀 這幾類問題。 髒讀 不可重複讀 幻讀 Read u