2016-04-29 163 views
0

我有一個'點擊'表,其中我每次用戶導航特殊計數器腳本click.php添加記錄。此表沒有自動增量列,它有transaction_id CHAR(32)作爲主鍵,它在插入新記錄之前隨機生成。每個新記錄都有列normalized=0MYSQL:死鎖與簡單查詢

每3分鐘後臺守護進程啓動一個事務,讀取所有新的點擊WHERE normalized=0並將其分組到stats。該表的唯一寫查詢是在所有處理結束時執行的UPDATE clicks SET normalized=1 WHERE normalized=0,然後是事務提交。

問題是,每次當click.php本次交易過程中導航時,腳本無法添加新記錄,以「點擊」和失敗,錯誤:

SQLSTATE[40001]: Serialization failure: 
1213 Deadlock found when trying to get lock; try restarting transaction 

    INSERT `clicks` 
    SET `transaction_id`='3520359d597ba05b635ff15feb334229', 
     `time`='2016-04-29 15:14:31', 
     ..., 
     `normalized`='0' 

我知道我可以解決這個問題使用LOCK TABLES,但我只想知道爲什麼會發生這種僵局。

UPD: 我看到下面的原因,在SHOW ENGINE INNODB STATUS輸出:

*** (1) WAITING FOR THIS LOCK TO BE GRANTED: 
RECORD LOCKS space id 252763 page no 124 n bits 480 index `normalized` 
of table `tds`.`clicks` trx id C1329EF lock_mode X locks gap before 
rec insert intention waiting 

回答

0

(這應該是一個評論,但其長期參與)

有什麼事務隔離模式?

我從來沒有遇到過這種情況 - 主要是因爲我避免使用多語句事務,例如,

UPDATE clicks 
SET normalized=2 
WHERE normalized=0; 

INSERT INTO stats (transaction_id, clicks) 
SELECT transaction_id, COUNT(*) 
FROM clicks 
WHERE normalized=2 
GROUP BY transaction_id; 

UPDATE clicks 
SET transaction_id=1 
WHERE transaction_id=2; 

有,如果你使用一個單獨的列和數據集生成標識與單個更新到點擊表這樣做的方法。如果你從cron運行這個,你應該把它們包裝在一個GET_LOCK()... RELEASE_LOCK()循環中以防止併發。雖然該模型確實支持大多數事務模型的併發性,但是當事情已經變糟時,它的性能會有所下降。