在進行SELECT 操做前,MyiSAM會給涉及到的表加讀鎖。這個時候其餘Session能夠正常對未加鎖的表進行操做。可是對加了讀鎖的表,只能對其進行查詢(共享鎖),對其修改則會阻塞,等待至表解鎖後,纔會生效。高併發
Session1 | Session2 |
---|---|
給TABLE_A加讀鎖 | 無操做 |
能夠對TABLE_A進行查詢,不能對TABLE_A進行修改 | 能夠對TABLE_A進行查詢,不能對TABLE_A進行修改 |
查詢修改 TABLE_B 報錯 | 查詢修改 TABLE_B正常 |
修改TABLE_A報錯 | 修改TABLE_A阻塞 |
Unlock tables;解鎖 | TABLE_A被修改 |
在進行寫操做前,MyiSAM會給涉及到的表加寫鎖。這個時候其餘Session能夠正常對未加鎖的表進行操做。可是對加了寫鎖的表,對其進行讀或寫,都會阻塞,直至寫鎖釋放後,纔會進行相應操做。post
Session1 | Session2 |
---|---|
給TABLE_A加寫鎖 | 無操做 |
能夠對TABLE_A進行修改,不能對TABLE_A進行查詢 | 不能對TABLE_A進行查詢,修改 |
不能對TABLE_B進行操做 | 能夠對TABLE_B進行操做 |
查詢TABLE_A報錯 | 查詢或者修改TABLE_A阻塞 |
Unlock tables;解鎖 | TABLE_A被查詢出結果或被修改 |
MyiSAM的讀寫鎖調度是寫優先,這也是MyiSAM不適合做爲以寫爲主的引擎。由於寫鎖後,其餘線程不能進行任何操做,大量的寫入操做會使得查詢很可貴到鎖,從而形成永久堵塞。優化
IMPORTANTspa
通俗地講:.net
讀鎖就是:我要備份,後面來的先別亂動(修改)東西;線程
寫鎖就是:我要修改,後面來的別急,排隊(無論你是要讀仍是要改,都得等我此次改完)。設計
InnoDB的鎖機制爲行鎖,行鎖支持事務。code
更新丟失:多個事務同時更新同一行的數據,而且不知道其餘事務的存在,致使最後有的更新失效(丟失)了。
髒讀:事務在更新數據的過程當中(已經修改了數據還沒有提交),去讀取數據,讀到了中間態的數據,這些數據不符合一致性要求,即爲髒讀。
不可重複讀:在一次的事務操做中,對某一數據進行了兩次(及以上)的讀操做,此時有另外一個事務在兩次讀操做的中間修改了數據,形成了兩次讀取的數據不一樣,即不能夠重複讀(否則數據會不同)。
幻讀:在一次的事務操做中,先讀取了幾行數據後,另外一個事務又增長或刪除了數據,在此以後,此事務又去讀取數據,發現數據憑空生成或消失,跟幻覺同樣,即幻讀。
總結:更新丟失爲多個事務幾乎同時修改數據出現的問題;髒讀爲一個事務在修改數據,另外一個事務讀取(SELECT)事務出現的問題;不可重複讀爲一個事務在查詢數據,中間有另外一個事務修改(UPDATE)了數據的問題;幻讀爲一個事務在查詢數據,另外一個事務在插入或刪除(INSERT or DELETE)數據的問題。
已提交讀與可重複讀是實際開發中最常用到的兩種事務隔離級別,這二者主要是經過MVCC(Multi Version Concurrency Control)對併發事務問題的解決。
Read Commited
的作法是在事務的每一條SQL語句執行前生成一個快照,此時其餘併發事務去讀取這個數據時,避免了髒讀的出現。Repeated Read
的作法是在事務的第一次查詢前生成一個快照,以後在這一次事務的讀取過程當中,都去讀取這一次快照,從而避免了髒讀和不可重複讀。總結鎖與隔離級別與併發問題的關係:
在默認的隔離級別下,咱們在對某幾行數據進行修改或者查詢的時候,只會鎖住這幾行數據不被修改,從而保證避免了不可重複讀的出現;而咱們即便對整張表全部行都進行操做了,那也是鎖住了這張表的全部行,而不是鎖住這張表,不能阻止表插入新的行,從而依然會出現幻讀的狀況(間隙鎖+行鎖的Next-Key Lock解決了此問題),而最高的隔離級別則是經過將事務串行化,咱們在執行查詢事務的同時是不可能有其餘事務來插入數據的,從而避免了幻讀的出現。
當咱們在查詢語句時,條件爲範圍查詢時,InnoDB無論這個區間是否有數據,都會將其鎖住,向這個區間的「間隙」(不存在的行)插入或刪除數據都會阻塞。
Next-Key Lock = Record Lock + Gap Lock InnoDB在默認隔離級別(Repeated Read)下,使用Next-Key Lock的方案解決了幻讀的問題。
即在進行範圍性的SELECT時,咱們先對已經存在的Records加上Record Lock
,再對此區間的間隙加上Gap Lock
,從而解決了幻讀的問題。
緣由:索引失效致使的全表掃描,使得從行鎖->表鎖。
select … for update 語句