事務用來保證數據庫的完整性——要麼都修改,要麼都不修改。事務必須知足ACID四個特性。mysql
ISO和ANIS SQL標準制定了四種事務隔離級別的標準:算法
InnoDB既支持行級鎖,也支持表級鎖,默認狀況下是採用行級鎖。
InnoDB存儲引擎實現了兩種標準的行級鎖:sql
InnoDB存儲引擎支持多粒度鎖定,容許行級鎖和表級鎖同時存在。爲了支持在不一樣粒度上進行加鎖操做,InnoDB存儲引擎提供了意向鎖。
意向鎖是表級別的鎖,其設計目的主要是爲了在一個事務中揭示下一行將被請求的鎖的類型。InnoDB存儲引擎支持兩種意向鎖:數據庫
意向鎖不會阻塞除全表掃描之外的任何請求。
併發
一致性的非鎖定讀(consistent nonlocking read)是指InnoDB存儲引擎經過多版本控制(multi versioning)
的方式來讀取當前執行時間數據庫中行的數據。若是讀取的行正在執行DELETE、UPDATE操做,這是讀取操做不會所以而等待行上鎖的釋放,相反,InnoDB存儲引擎會去讀取行的一個快照數據。以下圖所示:測試
上圖能夠看出,讀取的數據是一份快照數據,快照數據是指執行當前更改操做前的數據,該實現是經過undo段來實現的,因此快照數據自己是沒有額外的開銷的。由於快照數據是一份歷史數據,是隻讀的,因此不須要上鎖。
快照可能有多個版本,也就是說可能有多份不一樣的快照數據,這種技術稱爲行多版本技術
,由此帶來的併發控制稱爲多版本併發控制(Multi Version Concurrency Control, MVCC)
。
一致性非鎖定讀是InnoDB存儲引擎默認的讀取方式,可是不一樣的事務隔離級別下,讀取的方式不一樣,並非每一個事務隔離級別下讀取的都是一致性讀,即便都是一致性讀,不一樣的事務隔離級別讀取的快照數據也不一樣。例如Read Commited和Repeatable Read下,使用的都是一致性的非鎖定讀,但它們讀取的是不一樣的快照數據。在Read Commited級別下,讀取的老是被鎖定行的最新一份快照數據,而在Repeatable Read級別下,讀取的是事務開始時的第一份快照數據。atom
step 1. 初始化測試表 mysql> create table t (id int, -> primary key (id)) -> engine innodb; Query OK, 0 rows affected (0.62 sec) mysql> insert into t values(1); mysql> select * from t; +----+ | id | +----+ | 1 | +----+ 1 row in set (0.00 sec) step 2. 開啓一個會話A,並在會話A中開啓一個事務,查看下測試表的數據,但不提交事務 # Session A mysql> begin; Query OK, 0 rows affected (0.03 sec) mysql> select * from t; +----+ | id | +----+ | 1 | +----+ 1 row in set (0.00 sec) step 3. 開啓另外一個會話B,模擬併發的狀況,在會話B中開啓事務,修改測試表中id爲1的數據,但不提交 # Session B mysql> begin ; Query OK, 0 rows affected (0.00 sec) mysql> update t set id = 3 where id = 1; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 step 4. 在會話A中查看測試表數據,發現仍是修改以前的數據 # Session A mysql> select * from t; +----+ | id | +----+ | 1 | +----+ 1 row in set (0.00 sec) setp 5. 在會話B中提交事務 # Session B mysql> commit; Query OK, 0 rows affected (0.04 sec) step 5. 再在會話A中查看測試數據,在Read Commited和Repeatable Read級別下獲得的結果就不同了。對於Read Committed級別,它老是讀取最新版本,因此它獲得的結果是一個id爲3的記錄(幻讀)。而Repeatable Read級別下,它老是讀取事務開始時的行數據,因此它獲得的結果仍然是一個id爲1的記錄。
默認狀況下,InnoDB存儲引擎的Select操做使用的是一致性非鎖定讀,可是有些狀況下,須要用戶主動對讀取操做進行加鎖。InnoDB存儲引擎對Select語句加鎖有兩種操做:spa
對於一致性非鎖定讀,即便讀取的行已被使用Select ... For Update,也是能夠讀取的。Select ... For Update 和 Select ... Lock In Share Mode 必須在事務中使用,當事務提交了,鎖也就釋放了。
設計
InnoDB存儲引擎有3種行鎖算法:版本控制
Record Lock鎖住的永遠是索引而不是記錄
,若是在建表的時候沒有設置索引,InnoDB存儲引擎會使用隱式的主鍵來進行鎖定。多個事務同時修改同一行記錄,可能出現丟失更新的問題。
能夠看出,事務1的更新操做丟失了。避免丟失更新的作法,就是事務在查詢數據的時候加上排他鎖。
髒讀是指事務A讀到了事務B中尚未提交的更新(違反了數據庫的隔離性)。髒讀只在隔離級別爲Read UnCommitted的狀況下才會發生。避免髒讀的辦法,就是把事務的隔離級別至少設置成Read Committed。
幻讀是指在一個事務中屢次讀同一數據,拿到的結果不一樣(違反了數據庫的一致性)。例如,事務A讀了一行數據,事務B修改了這行數據並提交了,事務A再讀這行數據,拿到的結果與事務A前一次讀取的結果不一樣。 幻讀通常是能夠接收的,由於它讀到的確實是其餘事務已經提交的數據。 InnoDB存儲引擎中,經過使用Next-Key Lock算法來避免幻讀問題。在Next-Key Lock算法下,對於索引的掃描,不只僅鎖住的是掃描到的索引,並且還鎖住這些索引覆蓋的範圍(gap),所以在這個範圍內的修改都是不容許的。