1. 程式人生 > 其它 >MySQL資料庫——多使用者併發訪問鎖

MySQL資料庫——多使用者併發訪問鎖

多使用者共享資源,出現併發訪問的時候,需要合理控制資源的訪問規則。鎖就是用來實現這些訪問規則的重要資料結構。

根據加鎖的範圍,鎖可以大致分成全域性鎖、表級鎖、行鎖。

(1)全域性鎖就是對整個資料庫例項加鎖。

業務的更新不只是增刪改資料DML,還有可能是加欄位等修改表結構的操作DDL。

全域性讀鎖,使用Flush tables with read LOCK,做全庫邏輯備份,即把整個庫的每個表都select出來存成文字。這樣在備份過程中整個庫完全處於只讀的狀態,這樣業務就得停擺,而且備份期間從庫不能執行主庫同步的binlog,會導致主從延遲。

場景:使用者購買一個課程,業務邏輯就要扣掉他的餘額,然後往已購課程裡面加上一門課。

順序:先備份賬戶餘額,然後使用者購買,然後備份已購課程。會發現錢沒少,課多了。

也就是說,不加鎖的話,備份系統得到的不是一個邏輯時間點,這個檢視是邏輯不一致的。

官方自帶的邏輯備份工具是mysqldump,當mysqldump使用引數-single-transaction的時候,導資料之前就會啟動一個事務,確保拿到一致性檢視。由於MVCC的支援,這個過程資料可以正常更新。但是這個一致性讀的前提是引擎支援隔離級別(暗戳戳說MyISAM不行)

(2)表級鎖(一般不支援行鎖的才會想用這種)

一種是表鎖,一種是元資料鎖。

a、表鎖的語法:lock tables ...read/write。可以用unlock tables主動釋放鎖,也可以在客戶端斷開的時候自動釋放。

除了會限制別的執行緒的讀寫之外,也限定了本執行緒接下來的操作物件。

例如:執行緒A執行了lock tables t1 read, t2 write;

其他執行緒寫t1、讀寫t2的語句都會被阻塞。

同時,執行緒A執行unlock tables之前,也只能執行讀t1、讀寫t2的操作。不允許寫t1,也不能訪問其他表。

鎖住整個表還是不好用的,影響面太大了。

b、元資料鎖MDL。MDL的作用是保證讀寫的正確性,不需要顯示使用,訪問表的時候會被自動加上。

對一個表做增刪改查操作的時候,加MDL讀鎖。對錶做結構變更操作的時候,加MDL寫鎖。

事務中的MDL鎖,在語句執行開始時申請,但是語句結束之後並不會馬上釋放,而會等到整個事務提交之後再釋放。

(3)行鎖

行鎖是在引擎層由各個引擎自己實現的。

不是所有的引擎都支援行鎖,比如MyISAM就不支援。不支援行鎖就只能用表鎖,表鎖的話,同一張表在任何時刻都只能有一個更新在執行,會影響業務併發度。

如果使用了行鎖,可以在一個表設定很多鎖,並通過減少鎖衝突來提高業務併發度。

行鎖是針對資料表中記錄得鎖。比如鎖定一行,只有在事務A操作完成後事務B才能執行。

兩階段鎖:有兩個事務都要執行update操作,只有事務Acommit之後事務B才能執行操作。

因為在InnoDB事務中,行鎖是在需要的時候加上的,等待事務結束才能釋放。這就是兩階段鎖協議。

如果事務需要鎖很多行,要把最可能造成鎖衝突,最可能影響併發度的鎖儘量往後放。

當併發系統中不同執行緒出現迴圈資源依賴,涉及的執行緒都在等待別的執行緒釋放資源的時候,就會導致幾個執行緒都無限等待,即死鎖。

解決方案:直接進入等待,直到超時。這個超時時間通過innodb_lock_wait_timeout來設定。也可以主動發起死鎖檢測,發現死鎖就主動回滾死鎖鏈的事務,執行其他事務。將引數innodb_deadlock_detect設定成on就表示開啟這個邏輯。