Вместо FOR UPDATE
използвайте LOCK IN SHARE MODE
. FOR UPDATE
предотвратява и други транзакции да четат реда. LOCK IN SHARE MODE
позволява четене, но предотвратява актуализирането.
Справка:Ръководство за MySQL
------ сесия 1
START TRANSACTION;
SELECT * FROM test WHERE t=1 LOCK IN SHARE MODE;
UPDATE test SET NAME='irfandd' WHERE t=2;
COMMIT;
----- сесия 2 (която вече не се блокира :) )
START TRANSACTION;
UPDATE test SET NAME='irfandd' WHERE t=4;
COMMIT;
Актуализация:
Осъзнавайки, четаблицата няма индекс на t
, имам следното обяснение:
Първо, транзакция T1 заключва ред 1 в SELECT * FROM test WHERE t=1 FOR UPDATE
След това транзакция T2 се опитва да изпълни UPDATE test SET NAME='irfandd' WHERE t=4
. За да разбере кои редове са засегнати, той трябва да сканира всички редове, включително ред 1 . Но това е заключено, така че T2 трябва да изчака, докато T1 завърши. Ако има някакъв вид индекс, WHERE t=4
може да използва индекса, за да реши дали ред 1 съдържа t=4
или не, така че няма нужда да чакате.
Вариант 1: добавете индекс към test.t
така че вашата актуализация може да го използва.
Вариант 2: използвайте LOCK IN SHARE MODE
, който е предназначен само за поставяне на заключване за четене. За съжаление тази опция създава блокиране. Интересното е, че транзакцията T2 се изпълнява (актуализиране на ред 4), а T1 се проваля (актуализиране на ред 2). Изглежда, че T1 заключва ред 4 също и тъй като T2 го модифицира, T1 се проваля поради нивото на изолация на транзакциите (ПОВТОРЯЩО ЧЕТЕНЕ по подразбиране
). Окончателното решение би било да се играе с Нива на изолация на транзакциите , с помощта на READ UNCOMMITTED
или READ COMMITTED
нива на транзакции.
Най-простият еВариант 1 , IMHO, но зависи от вашите възможности.