Mysql

MySQL 一致的非鎖定讀取與 INSERT … SELECT

  • August 8, 2014

因此,通過閱讀 MySQL 5.5 文件以及與同事進行的一些實驗,我了解到情況如下:

  1. 對於 InnoDB 表,一個簡單的SELECT語句(不使用FOR UPDATEor的語句LOCK IN SHARE MODE)不會在該SELECT語句讀取的表上獲取任何行鎖。在所有事務隔離級別都是如此。
  2. 但是,如果您的事務隔離級別是REPEATABLE READ或更高,INSERT ... SELECTor語句將在它讀取CREATE TABLE AS SELECT的表上放置行鎖。

資料來源:

如果我正確理解這一點(如果我沒有正確理解,請糾正我),那麼我對這種差異感到困惑。當事務隔離級別相同時,為什麼在一種情況下讀取表需要鎖定行,而在另一種情況下不需要鎖定行?我想了解其中的原因。

來自MySQL 文件

對於未指定 FOR UPDATE 或 LOCK IN SHARE MODE 的子句(如 INSERT INTO … SELECT、UPDATE … (SELECT) 和 CREATE TABLE … SELECT)中的選擇,讀取的類型會有所不同:

預設情況下,InnoDB 使用更強的鎖,並且 SELECT 部分的行為類似於 READ COMMITTED,其中每個一致的讀取,即使在同一個事務中,設置和讀取自己的新快照。

要在這種情況下使用一致讀取,請啟用 innodb_locks_unsafe_for_binlog 選項並將事務的隔離級別設置為 READ UNCOMMITTED、READ COMMITTED 或 REPEATABLE READ(即除 SERIALIZABLE 之外的任何內容)。在這種情況下,不會對從選定表中讀取的行設置任何鎖。

顯然,僅在進行讀取時不需要更強的鎖。INSERT ... SELECT使用或將圖片複製到表格中CREATE TABLE ... SELECTSELECT需要是用於載入表的凍結快照。如果它是一個移動的目標,那將需要交易中的交易。如果您想要transaction within a transaction行為,則需要使用SAVEPOINT編寫腳本。否則,更強的鎖允許對原子 INSERT 進行一致的 SELECT。

做簡單SELECT的事情可以讓你的數據庫會話信任其他事務,而不是在你的數據視圖中玩煙霧和鏡子。如果它必須違反這種信任,它將禮貌地鎖定每一行以完成其工作,而不是欺騙只執行 SELECT 的 DB 會話認為數據是穩定的,而實際上它正在發生變化。

無論您選擇哪種隔離級別,它們都不是那麼精細,以至於一個簡單的 SELECT 都會被阻止。這就是為什麼SELECT ... FOR UPDATESELECT ... FROM ... LOCK IN SHARE MODE被發明,所以如果沒有禮貌不是一個選項,你可以變得那麼細化。

我之前寫過這個:如何使選擇語句被阻止?

引用自:https://dba.stackexchange.com/questions/73540