Mysql

MySQL:事務會鎖定行嗎?

  • March 5, 2017

我之前沒有嘗試過使用 MySQL 事務,我只是想澄清一些事情。

如果兩個使用者在非常精確的時間執行查詢,MySQL 將如何處理呢?例如,使用者正在嘗試更新記錄。

user1:更新表集column = column - 4 where column_id = 1;

user2: 更新表集 column = column - 7 where column_id = 1;

現在如果我使用事務,MySQL會選擇首先執行哪個查詢並鎖定第二個使用者,直到第一個查詢被送出?那是表鎖還是行鎖?

如果第三個使用者將發出選擇語句怎麼辦?MySQL 將返回的值是多少?

PS這將在Innodb上。

像這樣的單個語句與 MyISAM 或 InnoDB、事務或 autocommit=ON 相同。它阻塞了足夠的查詢,從而阻塞了另一個連接。完成後,另一個連接繼續進行。在所有情況下,該列很快都會減少 11。

第三個使用者可能會看到該值減少了 0 或 4 或 7 或 11。“非常精確的時間”實際上是不可能的,因為在執行每個語句的某個時間點,檢查/設置/任何單執行緒鎖. 也就是說,它們被序列化,速度快到你看不到。

InnoDB 只鎖定行,而不鎖定表。(好的,DDL 語句做更粗的鎖。)

更有趣的是修改兩件事的事務,或者需要相當長的時間:

**意向案例:**單項但需要時間:

BEGIN;
SELECT something;
think about it for a while
UPDATE that something;
COMMIT;

選擇需要這樣寫:

SELECT something  FOR UPDATE;

這告訴其他連接“我打算更新該行;請不要搞砸我”。(我舉了這個例子,因為很多新手都錯過了這個微妙之處。)

死鎖案例: 搞砸兩件事:

BEGIN;    -- in one connection
UPDATE thing_1;
UPDATE thing_2;
COMMIT;

BEGIN;    -- in another connection, at the "exact same time"
UPDATE thing_2;
UPDATE thing_1;
COMMIT;

這是僵局的典型例子——每個人都抓住一件東西,然後伸手去拿另一件東西。顯然它不能工作。一筆交易被殺死;另一個完成。因此,您必須檢查錯誤,以便發現它。

對死鎖的正常反應是重播整個失敗的事務。屆時,其他連接將不會受到干擾,並且應該可以順利進行。(好的,另一個連接可能會造成另一個死鎖。)

延遲案例:如果兩個連接以相同的順序抓取多個東西,那麼一個可以延遲到另一個完成。為了避免“永遠等待”,有一個預設的 50-second innodb_lock_wait_timeout。你這雙簡單UPDATEs的其實就是這種情況的一個例子。一個會及時完成;另一個停滯不前,直到第一個完成。

請注意死鎖如何(在某些情況下)通過始終如一地對您觸摸的事物進行排序而變成延遲。

autocommit=1: 使用此設置無需呼叫BEGIN,每條語句都有效:

BEGIN;
your statement
COMMIT;

autocommit=0: 這是等待發生的麻煩。執行寫入查詢時,BEGIN會隱式生成 a。但是,您有責任最終發出COMMIT. 如果您不這樣做,您會想知道為什麼您的系統會掛起。(另一個常見的新手錯誤。)我的建議:“永遠不要使用=0”。

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