我有表tt_users
其中有id
作爲主鍵,列state
(CHAR(1)),它可以是 「X」 或 「Y」,並state_position
(INT)找到。這些列上沒有索引。存儲引擎是innodb。MySQL的 - 死鎖時,試圖獲得鎖定
state_positions必須是連續的,並有可能永遠不會成爲某種狀態,即重複的位置,如果我有5個用戶狀態「X」,他們state_positions必須是1,2,3,4,5
這是我在運行查詢導致死鎖:
insert into `tt_users` (`state`, `state_position`)
values ('x',
(SELECT MAX(state_position) AS maxStatePosition
FROM tt_users AS u2
WHERE u2.state='x') + 1
)
爲了測試,我插入了大量用戶同時的,每一次我得到了僵局錯誤。
我看到這篇文章 - How to avoid mysql 'Deadlock found when trying to get lock; try restarting transaction',但我不明白,我應該用我的查詢,以防止死鎖做,如果這是在所有可能的,因爲這個問題的答案 - Working around MySQL error "Deadlock found when trying to get lock; try restarting transaction" - 說死鎖可能不管發生什麼。
我設法得到這個工作,始終工作的唯一辦法,就是這個(語言是PHP):
PDO::setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
然後手動鎖定表,並運行我的查詢:
SET autocommit=0;
LOCK TABLES
tt_users WRITE,
tt_users AS u2 WRITE;
insert into `tt_users` (`state`, `state_position`)
values ('x',
(SELECT MAX(state_position) AS maxStatePosition
FROM tt_users AS u2
WHERE u2.state='x') + 1
);
COMMIT;
UNLOCK TABLES;
然後:
PDO::setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
根據該方法我同時4次運行的代碼,每個實例inser幫助2500名用戶,沒有問題。
是否只有這樣才能使其發揮作用,或者我可以100%確定地防止死鎖而不必手動鎖定表?
UPDATE:
每@ wallyk的回答,我試過如下:
1)把查詢在事務 - 仍然死鎖錯誤
2)WITH CONSISTENT SNAPSHOT
開始交易,READ WRITE
, READ ONLY
。所有3個選項都需要設置PDO::setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
。 WITH CONSISTENT SNAPSHOT
和READ WRITE
仍然給我造成了死鎖錯誤,而READ ONLY
自然也沒有讓我執行INSERT
。
所以現在看來手動鎖定表是唯一可行的。
謝謝,我會嘗試所有這些,並得到結果。 – GTCrais
已經嘗試了您的建議並更新了結果。可悲的是,它沒有奏效。 – GTCrais