四種隔離級別說明
隔離級別 | 臟讀(Dirty Read) | 不可重復讀(NonRepeatable Read) | 幻讀(Phantom Read) |
---|---|---|---|
未提交讀(Read uncommitted) | 可能 | 可能 | 可能 |
已提交讀(Read committed) | 不可能 | 可能 | 可能 |
可重復讀(Repeatable read) | 不可能 | 不可能 | 可能 |
可串行化(SERIALIZABLE) | 不可能 | 不可能 | 不可能 |
臟讀 :一個事務讀取到另一事務未提交的更新數據
不可重復讀 : 在同一事務中,多次讀取同一數據返回的結果有所不同, 換句話說, 后續讀取可以讀到另一事務已提交的更新數據. 相反, “可重復讀”在同一事務中多次讀取數據時, 能夠保證所讀數據一樣, 也就是后續讀取不能讀到另一事務已提交的更新數據。
幻讀 :一個事務讀到另一個事務已提交的insert數據
事務隔離超通俗好懂的的講解
按照隔離的級別由低到高,越高的隔離,效率越差
0)、DEFAULT 默認隔離級別,由數據庫的數據隔離級別確定隔離級別
1)、READ_UNCOMMIYTTED 都未提交的 級別最低
允許別的事務,去讀取這個事務為提交之前的數據
缺點:可能會造成臟讀、幻讀、不可重復讀。
例子講解:店家對1000元商品進行降價500處理,數據更改,但未提交事務;
然后你查到降價將貨物並提交訂單; 可是商家由於操作異常,數據回滾,返回原價格1000;
這樣,在店家那邊是沒有操作成功的,可是在你這里卻得到了降價貨物訂單。
可理解為:外層更改價格的事務拉長執行,在執行之中出現提交訂單的事情,你讀了別人正在處理的數據。
2)、READ_COMMITTED 讀已提交級別
案例講解:你原本查詢商品價格為500,第二次為了證明真的降價了再查卻發現並沒有降價。
缺點:兩次讀的都是真的(不臟讀) 可是卻存在不可重復
可以理解為: 你兩次查詢為一次事務,將此事務拉長;
在此事務中間,有更改價格的操作,可能執行了多次,可是在這個多次執行修改中你無法插進去查一次;
只能等他更改完(中間事務結束)才能進行下一次查詢,你讀的期間別人插進來對數據操作了。
兩件事務出現了交集。
3)、REPEATABLE_READ 可重復讀 事務是多次讀取,得到的相同的值。
缺點: 會出現幻讀
即該事務執行期間,不允許其他事務對該事務數據進行操作,保證該事物中多次對數據的查詢結果一致。
就是你多次查詢的這個事務包含多條數據,為了保證讀取的一致性,可重復讀(REPEATABLE_READ)將使用的數據鎖起來不讓別人用。
4)、SERIALIZABLE 串行化讀 將事務排序,逐個執行事務提交了之后才會繼續執行下一個事務。
缺點:都隔離開了,效率慢
就是上面的可重復讀(REPEATABLE_READ)是將使用的數據范圍鎖起來不讓別人用,而這里是將涉及數據的表全都鎖起來,不允許別人操作。
這個事務的執行中,別的事務連在旁邊看的機會都沒有,完全不會有影響,你讀的時候別人看不到,隔離開,單獨執行。
整個事務排隊執行
本文為個人學習總結,可能會存在一些理解錯誤,或誤差,還請路過各位指點批評。
文章來源:http://blog.chinaunix.net/uid-20726500-id-5749804.html 作者:@小橋河西
初識MySQL的gap,覺得這個設計比較獨特,和其他數據庫的做法不太一樣,所以整理一個簡單的memo(雖然關於gap鎖,相關資料已經很多了)
一、什么是gap
A place in an InnoDB index data structure where new values could be inserted.
說白了gap就是索引樹中插入新記錄的空隙。相應的gap lock就是加在gap上的鎖,還有一個next-key鎖,是記錄+記錄前面的gap的組合的鎖。
二、gap鎖或next-key鎖的作用
http://dev.mysql.com/doc/refman/5.7/en/innodb-next-key-locking.html
To prevent phantoms, InnoDB uses an algorithm called next-key locking that combines index-row
locking with gap locking. InnoDB performs row-level locking in such a way that when it searches
or scans a table index, it sets shared or exclusive locks on the index records it encounters.
Thus, the row-level locks are actually index-record locks. In addition, a next-key lock on an index record also affects the “gap” before that index record. That is, a next-key lock is an index-record lock plus a gap lock on the gap preceding the index record. If one session has a shared or exclusive lock on record R in an index, another session cannot insert a new index record in the gap immediately before R in the index order.
簡單講就是防止幻讀。通過鎖阻止特定條件的新記錄的插入,因為插入時也要獲取gap鎖(Insert Intention Locks)。
三、什么時候會取得gap lock或nextkey lock
這和隔離級別有關,只在REPEATABLE READ或以上的隔離級別下的特定操作才會取得gap lock或nextkey lock。
http://dev.mysql.com/doc/refman/5.7/en/innodb-transaction-isolation-levels.html
REPEATABLE READ
... For consistent reads, there is an important difference from the READ COMMITTED isolation level:
All consistent reads within the same transaction read the snapshot established by the first read. ...
For locking reads (SELECT with FOR UPDATE or LOCK IN SHARE MODE), UPDATE, and DELETE statements, locking depends on whether the statement uses a unique index with a unique search condition, or a range-type search condition. For a unique index with a unique search condition, InnoDB locks only the index record found, not the gap before it. For other search conditions, InnoDB locks the index range scanned, using gap locks or next-key locks to block insertions by other sessions into the gaps covered by the range.
locking reads,UPDATE和DELETE時,除了對唯一索引的唯一搜索外都會獲取gap鎖或next-key鎖。即鎖住其掃描的范圍。
下面對非唯一索引做個測試。
表定義如下:
mysql> show create table tb2;
+-------+------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+------------------------------------------------------------------------------------------------------------------------------------------------+
| tb2 | CREATE TABLE `tb2` (
`id` int(11) DEFAULT NULL, `c1` int(11) DEFAULT NULL, KEY `tb2_idx1` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 | +-------+------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec)
表中有3條記錄: 10,20,30。
mysql> select * from tb2;
+------+------+
| id | c1 | +------+------+ | 10 | 0 | | 20 | 0 | | 30 | 0 | +------+------+ 3 rows in set (0.01 sec)
在REPEATABLE READ下,更新一條記錄不提交,然后看看能阻塞另外的會話哪些操作。
SESSION 1:
SESSION 1中更新id=20的記錄
mysql> begin;
Query OK, 0 rows affected (0.00 sec) mysql> update tb2 set c1=2 where id=20; Query OK, 1 row affected (0.04 sec) Rows matched: 1 Changed: 1 Warnings: 0
SESSION 2:
SESSION 2中,執行插入操作,發現[10,30)范圍不能插入數據。
mysql> begin;
Query OK, 0 rows affected (0.00 sec) mysql> insert into tb2 values(9,4); Query OK, 1 row affected (0.00 sec) mysql> insert into tb2 values(10,4); ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction mysql> insert into tb2 values(19,4); ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction mysql> insert into tb2 values(20,4); ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction mysql> insert into tb2 values(21,4); ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction mysql> insert into tb2 values(29,4); ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction mysql> insert into tb2 values(30,4); Query OK, 1 row affected (0.01 sec)
對於更新操作,僅20這條記錄不能更新,因為更新操作不會去獲取gap鎖。
mysql> begin;
Query OK, 0 rows affected (0.00 sec) mysql> update tb2 set c1=4 where id=10; Query OK, 0 rows affected (0.00 sec) Rows matched: 1 Changed: 0 Warnings: 0 mysql> update tb2 set c1=4 where id=20; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction mysql> update tb2 set c1=4 where id=30; Query OK, 0 rows affected (0.00 sec) Rows matched: 2 Changed: 0 Warnings: 0
如果SESSION 1的表掃描沒有用到索引,那么gap或next-key鎖住的范圍是整個表,即任何值都不能插入。
READ COMMITTED
For locking reads (SELECT with FOR UPDATE or LOCK IN SHARE MODE), UPDATE statements, and DELETE statements, InnoDB locks only index records, not the gaps before them, and thus permits the free insertion of new records next to locked records.
只會鎖住已有記錄,不會加gap鎖。
SERIALIZABLE
This level is like REPEATABLE READ, but InnoDB implicitly converts all plain
SELECT statements to SELECT ... LOCK IN SHARE MODE if autocommit is disabled.
和REPEATABLE READ的主要區別在於把普通的SELECT變成SELECT … LOCK IN SHARE MODE,即對普通的select都會獲取gap鎖或next-key鎖。
REPEATABLE READ和幻讀
在“consistent-read”時,REPEATABLE READ下看到是事務開始時的快照,即使其它事務插入了新行通常也是看不到的,所以在常見的場合可以避免幻讀。 但是,”locking read”或更新,刪除時是會看到已提交的修改的,包括新插入的行。
http://dev.mysql.com/doc/refman/5.7/en/innodb-consistent-read.html
If you want to see the “freshest” state of the database, use either the READ COMMITTED isolation level or a locking read:
下面看一個例子
SESSION 1:
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec) mysql> select id,c1 from tb1 where id=1; +----+------+ | id | c1 | +----+------+ | 1 | 100 | +----+------+ 1 row in set (0.00 sec)
SESSION 2:
mysql> update tb1 set c1=101 where id =1; Query OK, 1 row affected (0.03 sec) Rows matched: 1 Changed: 1 Warnings: 0
SESSION 1:
mysql> select id,c1 from tb1 where id=1 LOCK IN SHARE MODE; +----+------+ | id | c1 | +----+------+ | 1 | 101 | +----+------+ 1 row in set (0.00 sec) mysql> select id,c1 from tb1 where id=1; +----+------+ | id | c1 | +----+------+ | 1 | 100 | +----+------+ 1 row in set (0.00 sec) mysql> update tb1 set c1=c1+1000 where id=1; Query OK, 1 row affected (0.02 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select id,c1 from tb1 where id=1; +----+------+ | id | c1 | +----+------+ | 1 | 1101 | +----+------+ 1 row in set (0.00 sec)
上面update的行為違反了REPEATABLE READ的承諾,看到了事務開始后其它事務的並發更新。這對應用開發需要特別注意,這種情況下其它數據庫通常都是報錯的。
其它
RR和RC相比還有一個重要的區別,RC下,掃描過但不匹配的記錄不會加鎖,或者是先加鎖再釋放,即semi-consistent read。但RR下掃描過記錄都要加鎖。這個差別對有全表掃描的更新的場景影響極大。詳細參考http://hedengcheng.com/?p=771,關於MySQL的加鎖處理,這篇文章講得很透徹!
參考
- http://hedengcheng.com/?p=771
- http://dev.mysql.com/doc/refman/5.7/en/innodb-consistent-read.html
- http://dev.mysql.com/doc/refman/5.7/en/innodb-transaction-isolation-levels.html
- http://dev.mysql.com/doc/refman/5.7/en/innodb-next-key-locking.html
- http://blog.chinaunix.net/uid-20726500-id-3902528.html
- http://blog.itpub.net/22664653/viewspace-750824/
- http://www.bitscn.com/pdb/mysql/201405/227973.html