Mysql-innodb事務、鎖以及MVCC併發版本控制

一、事務sql

  1.1 事務的四大特性數據庫

  • 原子性(Atomicity):原子性是指事務包含的全部操做要麼所有成功,要麼所有失敗回滾。
  • 一致性(Consistency):一致性是指事務必須使數據庫從一個一致性狀態變換到另外一個一致性狀態,也就是說一個事務執行以前和執行以後都必須處於一致性狀態。拿轉帳來講,假設用戶A和用戶B二者的錢加起來一共是5000,那麼無論A和B之間如何轉帳,轉幾回帳,事務結束後兩個用戶的錢相加起來應該還得是5000,這就是事務的一致性。
  • 隔離性(Isolation): 隔離性是當多個用戶併發訪問數據庫時,好比操做同一張表時,數據庫爲每個用戶開啓的事務,不能被其餘事務的操做所幹擾,多個併發事務之間要相互隔離。
  • 持久性(Durability):持久性是指一個事務一旦被提交了,那麼對數據庫中的數據的改變就是永久性的,即使是在數據庫系統遇到故障的狀況下也不會丟失提交事務的操做。

1.2 併發事務帶來的問題併發

  • 髒讀:指在一個事務處理過程裏讀取了另外一個未提交的事務中的數據。好比用戶A的帳戶裏有500元,事物T1:將money-100=400,可是該事物還未提交。 事物T2:讀取用戶A的帳戶,查看到A的帳戶有400。而後事物1回滾,用戶A的帳戶又變回了原來的500。 事物T2就產生了髒讀。
  • 不可重複讀:不可重複讀是指A事務讀取了B事務已經提交的更改數據。假設A在取款事務過程當中查詢帳戶餘額,B往該帳戶轉帳100後,A再次查詢帳戶餘額,會發現兩次讀取帳戶的餘額發生不一致。不可重複讀和髒讀的區別是,髒讀是某一事務讀取了另外一個事務未提交的髒數據,而不可重複讀則是讀取了前一事務提交的數據。
  • 幻讀:A事務讀取到了B事務的新增數據。A事務統計存款帳戶的總金額爲10000,這時B事務新增了一個帳戶存款爲100,A事務再次統計總金額10100(產生了幻讀)。幻讀與不可重複讀的區別,幻讀讀取了其餘事務新增的數據,不可重複讀,讀取了其餘事務的更改(或者刪除)數據。

 

1.3 事務的隔離級別性能

爲了達到上述事務特性,數據庫定義了幾種不一樣的事務隔離級別:spa

  • READ_UNCOMMITTED(未提交讀): 最低的隔離級別,容許讀取還沒有提交的數據變動,可能會致使髒讀、幻讀或不可重複讀
  • READ_COMMITTED(提交讀): 容許讀取併發事務已經提交的數據,能夠阻止髒讀,可是幻讀或不可重複讀仍有可能發生
  • REPEATABLE_READ(可重複讀): 對同一字段的屢次讀取結果都是一致的,除非數據是被自己事務本身所修改,能夠阻止髒讀和不可重複讀,但幻讀仍有可能發生(Mysql innodb存儲引擎經過一些特殊的處理,在該隔離級別解決了幻讀問題)。
  • SERIALIZABLE(串行): 最高的隔離級別,徹底服從ACID的隔離級別。全部的事務依次逐個執行,這樣事務之間就徹底不可能產生干擾,也就是說,該級別能夠防止髒讀、不可重複讀以及幻讀。可是這將嚴重影響程序的性能。一般狀況下也不會用到該級別。

這裏須要注意的是:Mysql 默認採用的 REPEATABLE_READ隔離級別。版本控制

二、Innodb的鎖blog

Innodb 與 MyISAM 最大的不一樣在於:一是支持事務,二是採用行級鎖。索引

共享鎖:又稱爲讀鎖,簡稱S鎖,顧名思義,共享鎖就是多個事務對於同一數據能夠共享一把鎖,都能訪問到數據,可是隻能讀不能修改;
加鎖釋鎖方式:
select * from procuct WHERE id=1 LOCK IN SHARE MODE;事務

排他鎖:
又稱爲寫鎖,簡稱X鎖,排他鎖不能與其餘鎖並存,如一個事務獲取了一個數據行的排他鎖,其餘事務就不能再獲取該行的鎖(共享鎖、排他鎖),只有獲取了排他鎖的事務才能夠對數據行進行讀取和修改,(其餘事務要讀取數據可來自於快照)。ci

意向共享鎖(IS):表示事務準備給數據行加入共享鎖,即一個數據行加共享鎖前必須先取得該表的IS鎖,意向共享鎖之間是能夠相互兼容的
意向排它鎖(IX):表示事務準備給數據行加入排他鎖,即一個數據行加排他鎖前必須先取得該表的IX鎖,意向排它鎖之間是能夠相互兼容的
意向鎖(IS、IX)是InnoDB數據操做以前自動加的,不須要用戶干預。


爲何須要意向鎖?

假如事務A鎖住表中的一行(寫鎖),事務B鎖住整個表(寫鎖)。若是沒有意向鎖,事務A既然鎖住了某一行,其餘事務就不可能修改這一行。這與」事務B鎖住整個表就能修改表中的任意一行「造成了衝突。因此,沒有意向鎖的時候,行鎖與表鎖共存就會存在問題!有了意向鎖以後,事務A在申請行鎖(寫鎖)以前,數據庫會自動先給事務A申請表的意向排他鎖。當事務B去申請表的寫鎖時就會失敗,由於表上有意向排他鎖以後事務B申請表的寫鎖時會被阻塞。

加鎖方式:
delete / update / insert 默認加上X鎖
SELECT * FROM table_name WHERE ... FOR UPDATE

InnoDB的行鎖實現方式:

經過給索引上的索引項加鎖來實現的,若是沒有索引,InnoDB將對錶中的全部記錄加鎖,實際效果跟表鎖同樣。

InnoDB的行鎖分爲三種狀況:

  • Next-key locks:鎖住記錄+區間(左開右閉),當sql執行按照索引進行數據的檢索時,查詢條件爲範圍查找(between and、<、>等)並有數據命中則此時SQL語句加上的鎖爲Next-key locks,鎖住索引的記錄+區間(左開右閉)。若是有一張表,用sql 「SELECT * FROM product WHERE id > 3 AND id < 6 FOR UPDATE;」 去查詢,那麼該條語句會鎖住(5,7] 這之間的數據。 這時候向表中插入id爲6的數據,是會被阻塞。

  • Gap locks:鎖住數據不存在的區間(左開右開),當sql執行按照索引進行數據的檢索時,查詢條件的數據不存在,這時SQL語句加上的鎖即爲Gap locks,鎖住索引不存在的區間(左開右開)。當用「SELECT * FROM product WHERE id > 2 AND id < 4 FOR UPDATE;」去查詢,查不到數據,此時會鎖住(1,5)區間的數據。
  • Record locks:鎖住具體的索引項,當sql執行按照惟一性(Primary key、Unique key)索引進行數據的檢索時,查詢條件等值匹配且查詢的數據是存在,這時SQL語句加上的鎖即爲記錄鎖Record locks,鎖住具體的索引項。當使用SELECT * FROM product WHERE id =2 FOR UPDATE 去查詢,它會鎖住id爲2的這一行記錄。

 

三、MVCC併發版本控制

MVCC就是同一條數據能夠同時存在多個版本:更新數據時,先插入一條新記錄,而後把舊記錄標記爲刪除;查詢時只查詢事務開始前就已存在的記錄。

  • 快照讀:select語句默認,不加鎖,MVCC實現可重複讀,使用的是MVCC機制讀取undo中的已經提交的數據。因此它的讀取是非阻塞的。
  • 當前讀:select語句加S鎖或X鎖;全部的修改操做加X鎖。

RR隔離級別下的快照讀,不是以begin開始的時間點做爲snapshot創建時間點,而是以第一條select語句的時間點做爲snapshot創建的時間點。

相關文章
相關標籤/搜索