概述:鎖分爲樂觀鎖和悲觀鎖,cas鎖是樂觀鎖,mysql中的讀鎖和寫鎖都是悲觀鎖。
cas鎖:修改數據時判斷數據版本號是不是修改以前的數據,若是數據已經被修改則放棄本次修改或者取出最新數據從新進行計算修改直到修改爲功。
讀鎖(共享鎖):給數據加讀鎖,全部事務線程均可以讀取數據,但除了當前線程以外其餘線程對數據的新增和修改會被阻塞。
寫鎖(排它鎖):除當前線程以外,其餘線程對鎖定數據的全部操做(增刪改查)均會被阻塞。mysql
表鎖:鎖定整張表,語法以下sql
//讀鎖 lock table user read; //寫鎖 lock table user write;
PS:鎖通常是加載索引上,而不是數據上
數據庫
事務的ACID屬性
原子性(Atomicity):一個事務應當看作一個最小的總體,事務內的要作要麼都成功,要麼都失敗。
一致性(Consistent):事務先後的數據應該保持一致的變動,要麼都變動,要麼都回滾
隔離性(Isolation):事務和事務之間應該互相隔離,一個事務不該該受到其餘事務的操做影響。
持久性(Durable):事務的執行結果應該是永久的,就算服務器宕機了也會保存下來。
mysql事務隔離分爲四個等級緩存
隔離級別 | 髒讀 | 不可重複度 | 幻讀 |
---|---|---|---|
讀未提交 | 可能 | 可能 | 可能 |
讀已提交 | 不可能 | 可能 | 可能 |
可重複讀 | 不可能 | 不可能 | 可能 |
可串行化 | 不可能 | 不可能 | 不可能 |
髒讀:一個事務在執行時讀取到了另外一個事務未提交的數據修改,違背了事務的隔離性
不可重複讀:一個事務在屢次讀取同一條數據時該數據的狀態不一樣,例如第一次是1,第二次是2,這種會形成邏輯混亂的狀況稱爲不可重複讀
幻讀:一個事務能夠操做本不該該存在(查詢不到)的數據,該狀況稱之爲幻讀,例如事務A在執行過程當中,事務B提交了修改,那麼即便事務A看不到事務B的修改,也能夠修改事務B變化後的數據,該狀況稱之爲幻讀服務器
讀未提交:不作隔離,任何操做都是全局操做
讀已提交:事務只有在commit以後纔會產生全局影響,沒有commit以前全部的數據不會產生真實的變化。
可重複讀:事務之間互相隔離,一個事務在生成事務ID後全部其餘事務對數據的修改都再也不會體如今該事務內的查詢之中
可串行化:全部的操做由並行改成單線程執行。架構
mysql事務中的讀已提交和可重複度兩種隔離機制都用到了mvcc機制。併發
mvcc機制簡單來講有如下幾點。mvc
1:事務在began的時候並無生成事務ID,在執行第一條查詢sql的時候纔會生成事務ID。 2:事務ID生成時會同時生成一個read view,read view裏保存全部當前已開始但未提交的事務ID以及一個已提交的數字最大的事務ID。 3:在查詢數據時從undo版本鏈中尋找數據的歷史版本,排除掉全部read裏存儲的當前未提交的事務對數據的修改和大於查詢時提取的最大事務ID的事務對數據的修改以後返回數據(簡單來講就是排除掉在生成read view時全部未提交/未建立的事務對數據的修改結果。)
讀已提交和可重複讀中mvcc機制實現的異同
讀已提交在執行每條查詢sql時會從新生成read view,因此已提交的事務對數據產生的影響都能查出來,兩次讀取結果可能不同。
可重複度只有在執行第一條查詢sql時候生成一次read view,因此一個事務中不管讀取多少次,結果都是同樣的。spa
PS:數據隔離只是隔離了查詢結果,最終修改時仍是會按照修改時數據庫中的真實數據進行修改,因此在修改時依舊要考慮數據可能已經被其餘的事務修改了的可能性
線程
mysql默認的隔離級別是可重複度,可重複讀在某些狀況下可使用間隙鎖解決幻讀的問題。
間隙鎖(Gap Lock)
假如數據庫中的數據有過刪除,ID 爲1,2,4,10,20
那麼數據庫中的間隙就有(2,4)(4,10)(10,20)(20,正無限)四組
此時若是對這四組間隙之間的ID進行操做,例如:
update user set name =‘s1’ where id >10 and id <25;
那麼,因爲條件的範圍跨越了(10,20)(20,正無限)兩組間隙,那麼id位於這兩組間隙之中的全部數據在該update進行commit前都會阻塞。
例如
update user set name =‘s2’ where id =11;
就會被阻塞,沒法執行
臨鍵鎖(Next-key Locks)
臨鍵鎖的概念創建在間隙鎖上,若是修改語句改爲下面這樣:
update user set name =‘s1’ where id >10 and id <19;
條件只跨越了(10,20)一組間隙,那麼對ID是20的數據也沒法修改,但對ID是10的能夠修改,這就是臨鍵鎖,隙範圍之中,位於最後的那個值的數據也將被鎖定。
無索引行鎖會升級爲表鎖
InnoDB的行鎖是針對索引加的鎖,不是針對記錄加的鎖。而且該索引不能失效,不然都會從行鎖升級爲表鎖
首先明確一個概念,mysql的數據磁盤讀寫是隨機讀寫,效率不高,而且在進行磁盤讀取時中間有一層緩存,並不必定是直接讀取的磁盤,詳細邏輯以下:ps:圖上忘記畫了,數據修改的第三步是修改緩存中的數據
直接對磁盤上的數據文件進行隨機讀取效率是很慢的,上面的執行邏輯雖然看似複雜,但避免了每次對磁盤數據文件進行隨機讀取,對緩存的讀取和文件IO比起來效率要快上許多倍,同時利用多個日誌文件保證了數據的一致性,並且對日誌文件的讀寫是順序讀寫,效率也會比隨機讀取數據文件快不少,就算宕機也能夠保證數據的一致性。基於這個架構mysql才能同時支撐大量的併發產生。