1.全局鎖就是對整個數據庫實例加鎖。MySQL 提供了一個加全局讀鎖的方法,命令是Flush tables with read lock
,即FTWRL。
MySQL全局鎖是一種數據庫級別的鎖,用於在執行特定操作時阻塞其他會話對數據庫的訪問。當全局鎖被獲取時,其他會話的讀寫操作將被暫停,直到全局鎖被釋放。
全局鎖適用於需要對整個數據庫進行一致性操作或維護任務的場景,例如備份、數據庫遷移、表結構變更等。通過獲取全局鎖,可以確保在執行這些操作期間,數據庫保持在一個一致的狀態,避免數據不一致或損壞。
全局鎖的獲取通過執行FLUSH TABLES WITH READ LOCK
語句來實現。該語句會獲取一個全局只讀鎖,並阻塞其他會話對數據庫的寫操作,但允許其他會話的讀操作繼續進行。在獲取全局鎖後,可以執行需要的操作,然後使用UNLOCK TABLES
語句來釋放全局鎖。
以下是一個示例,演示如何使用全局鎖:
-- 獲取全局鎖
FLUSH TABLES WITH READ LOCK;
-- 執行需要的操作,例如備份數據庫
-- ...
-- 釋放全局鎖
UNLOCK TABLES;
在上述示例中,通過執行FLUSH TABLES WITH READ LOCK
語句獲取了全局鎖。在獲取全局鎖期間,其他會話的寫操作將被阻塞,但讀操作仍然允許進行。在執行需要的操作(例如備份數據庫)後,使用UNLOCK TABLES
語句釋放全局鎖,從而恢復正常的數據庫訪問。
需要注意的是,獲取全局鎖會對數據庫的正常運行產生影響,因爲它會阻塞其他會話的寫操作。所以,在使用全局鎖時需要謹慎,並確保在必要時使用,並在操作完成後及時釋放全局鎖,以允許其他會話繼續正常操作數據庫。
當你需要讓整個庫處於只讀狀態的時候,可以使用這個命令,之後將會禁止該數據庫中的數據更新和表的結構修改操作,一般在對整個庫進行邏輯備份時使用。
在對整個庫進行邏輯備份時,如果不加全局鎖,由於數據庫的備份不可能一瞬間完成,那麼將可能造成最終數據不一致的問題。
比如有一個用戶餘額表,一個商品表,邏輯是用戶先在餘額表中扣款,然後在商品表中添加購買的商品。假設在此處操作的餘額表扣款之前發起了數據庫備份,首先備份的餘額表,那麼此時備份的餘額表並沒有在此次交易中扣款,在備份餘額表之後,餘額表發起了扣款,並且商品表增加了商品信息,此時備份到商品表,那麼備份的商品表中增加了本次交易的商品。最終結果就是在備份的數據之中,餘額表並沒有扣款,但是商品表中增加了商品,這樣商家就承擔了損失。而如果是先添加商品,然後扣款的話,那麼最終可能導致商品沒有添加,但是被扣了款,那麼用戶就會來找你了!
也就是說,不加鎖的話,備份系統備份的得到的庫不是一個邏輯時間點,這個視圖是邏輯不一致的。
對於整個數據庫加全局鎖的確會非常的影響性能:
-
整個數據庫變得只讀,那麼正常的業務邏輯肯定會受到影響,業務基本上就得停擺;
-
如果你在主庫上備份,那麼在備份期間都不能執行更新,業務基本上就得停擺;
-
如果你在從庫上備份,那麼備份期間從庫不能執行主庫同步過來的binlog,會導致主從延遲。
對於事務性執行引擎來說,還可以使用官方自帶的邏輯備份工具是mysqldump
,他利用了MVCC的一致性視圖的原理,當mysqldump
使用參數–single-transaction
的時候,導數據之前就會啓動一個事務,來確保拿到一致性視圖,而由於MVCC
的支持,這個過程中數據是可以正常更新的。
對於MyISAM
這種不支持事務的引擎,如果備份過程中有更新,總是隻能取到最新的數據,那麼就破壞了備份的一致性。這時,我們就需要使用FTWRL命令而不能使用mysqldump了。
2.還有一種方法,那就是使用set global readonly=true
的方式,
讓整個數據庫變得只讀,但這種方式並不推薦:
在有些系統中,readonly
的值會被用來做其他邏輯,比如用來判斷一個庫是主庫還是備庫。因此修改 global 變量的方式影響面更大,不建議適用。
在異常處理機制上有差異,如執行 FTWRL 命令之後由於客戶端發生異常斷開,那麼 MySQL 會自動釋放這個全局鎖,整個庫回到可以正常更新的狀態。而將整個庫設置爲 readonly 之後,如果客戶端發生異常,則數據庫就會一直保持 readonly 狀態,這樣會導致整個庫長時間處於不可寫狀態,風險較高。
3. 總結
記住,業務的更新不只是增刪改數據(DML),還有可能是加字段等修改表結構的操作(DDL)。不論是哪種方法,一個庫被全局鎖上之後,你要對裏面任何一個表做更改操作,都會被鎖住的。