資料庫中有很多鎖,但鎖是為瞭解決什麼問題?具體都有哪些鎖呢?這篇文章簡單對MySQL中的鎖做了一個總結 一、鎖的設計是為瞭解決什麼問題? 當多用戶讀寫數據的時候,就有可能會出現同一時刻對同一條數據的讀寫,如果是大家都只是對同一條數據進行讀,無所謂,大家讀到數據都是一樣的,但當有的想要讀取數據,有的想 ...
我學習MySQL是半路出家,剛開始接觸的時候,只知道資料庫的增刪改查和事務,直到有一天資料庫突然爆出(1205, 'Lock wait timeout exceeded; try restarting transaction'),那時候,我才知道資料庫還有鎖這麼一個玩意。這篇文章簡單談談我對MySQL鎖的理解與總結
一、鎖的設計是為瞭解決什麼問題?
我們知道資料庫能夠支持多用戶共同讀寫,當多用戶讀寫數據的時候,就有可能會出現同一時刻對多個用戶對同一條數據的讀寫,就會出現下麵的場景:
- 大家都只是對這一條數據進行讀取
- 有一部分人想要對這一條數據進行讀取,有一部分人想要對這一條數據進行修改
- 大家都想要對這一條數據進行修改
對於場景1,數據不會變化,大家讀到數據都是一樣的,
對於場景2,若讀數據的人不關心修改後的數據,只關心當前的值,對於讀數據的人是沒有影響的,對於修改數據的人,問題就出現了,大家都拿去修改了,然後保存了自己修改的值,這樣的話,我們要以誰修改的值為準呢,或者後面保存修改值的人會把前面保存的結果給覆蓋掉。
對於場景3,寫數據會出現和場景2一樣的情況。
如何優雅的解決上面的問題呢?資料庫引入了鎖的概念,數據可以加鎖,用來控制對數據的合理訪問。對於上面的場景3,當用戶1想要修改這一條數據時,必須先獲取這一條數據的鎖,然後在修改,同時用戶2想要修改這一條數據時,也要先獲取這一條數據的鎖,但鎖被用戶1獲取了,他只能等用戶1修改完,釋放鎖後,才能繼續修改這一條數據,這樣每個人都能修改數據,就不會亂了。
根據鎖的類型可以分為讀鎖,寫鎖
根據鎖的範圍可以分為全局鎖,表級鎖,行鎖
二、讀鎖,寫鎖
當我們需要對一個數據進行讀取的時候,就需要獲取讀鎖,當我們對一個數據進行修改的時候,就需要獲取寫鎖
讀鎖之間不互斥,當對一個數據加了讀鎖後,還可以對它繼續加讀鎖,不能添加寫鎖
寫鎖與讀鎖之間,寫鎖與寫鎖之間互斥,當對一個數據加了寫鎖後,不能繼續添加其他鎖了,必須要等待寫鎖釋放
三、全局鎖
全局鎖,會鎖住整個資料庫,整個資料庫不可寫入數據,不可修改數據表結構,只能讀取數據,這樣的話,就保證了整個資料庫只讀,最典型的應用就是全局備份數據,備份數據期間,我們不希望有數據能寫入資料庫中,不然後有可能備份後的數據是不完整的數據。
比如有兩個表中的數據是關聯的,第一張表a,第二張表b,表a增加一條記錄時,表b就會記錄一條關於表a操作的記錄
現在在我們備份的時候,不加全局鎖,考慮下麵的情況
時刻1. 備份表a
時刻2. 表a插入了一條記錄,表b也要記錄一條
時刻3. 備份表b
這樣的順序下來,備份後的數據表b中多記錄了一次操作
我們可以通過加全局鎖,來實現在備份過程中,只能讀取數據,無法修改數據,來保證備份後數據的一致性
四、表級鎖
表級鎖可分為兩種,一種是表鎖,一種元數據鎖(MDL)
MDL鎖不需要顯示使用,在訪問表的時候會自動加上
當要讀取一個表時,要獲取MDL讀鎖,當要修改一個表的結構的時候,就要獲取MDL寫鎖。MDL主要是為了防止DDL和DML併發的衝突。
表鎖鎖一整表,鎖的範圍還是太大了。
五、行鎖
行鎖時目前最細粒度的鎖了,只有Innodb引擎支持,MYISAM引擎只支持到表級鎖
innodb事務開啟後,行鎖是需要的時候才會加上,但不是不需要了就會立即釋放行鎖,而是等整個事務提交之後,才會釋放行鎖。這個就是mysql的兩階段鎖協議。
有這麼一種場景,一個事務執行中,要執行很多條語句,其中有一條語句會更新同一行數據。當多個事務併發的時候,必定會爭奪同一行數據的鎖,當一個事務持有鎖的時候,其他事務就必須等待。在這種場景下,我們該如何設計語句的執行順序,讓等待的時間最少?
我們已經知道了兩階段鎖協議,鎖在事務結束的時候才會釋放,所以,把更新同一行數據的語句越往後放,等待的時間就會越少。
innodb已經有了行鎖,但還是不能夠保證併發事務的正確性,為此,innodb引入了新的鎖,叫間隙鎖,當要更新數據時,在一行行掃描加鎖的過程中,不僅會加行鎖,還會添加間隙鎖,也就數據行之間的鎖。
六、總結
MySQL中的鎖機制就是為瞭解決共用資源的問題,為了從不同程度控制資源的讀寫,相應的引入了全局鎖,表級鎖,行鎖,以及不同鎖類型。