MySQL:事務會鎖定行嗎?
我之前沒有嘗試過使用 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
”。