Я получаю ошибку мертвой блокировки в своей mysql транзакции.
Простой пример моей ситуации:
Thread1 > BEGIN;
Query OK, 0 rows affected (0.00 sec)
Thread1 > SELECT * FROM A WHERE ID=1000 FOR UPDATE;
1 row in set (0.00 sec)
Thread2 > BEGIN;
Query OK, 0 rows affected (0.00 sec)
Thread2 > INSERT INTO B (AID, NAME) VALUES (1000, 'Hello world');
[Hangs]
Thread1 > INSERT INTO B (AID, NAME) VALUES (1000, 'Hello world2');
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
Thread2 >
Query OK, 1 row affected (10.00 sec)
B.AID является FOREIGN KEY, относящимся к A.ID
Я вижу три решения:
Есть ли какие-либо другие решения?
На основе функции из блога о высокой производительности mysql.
Мне удалось реализовать следующий код обработки тупиковых ситуаций в PHP:
/* maximum number of attempts for deadlock */
$MAX_ATTEMPS = 20;
/* query */
$sql = "INSERT INTO B (AID, NAME) VALUES (1000, 'Hello world')";
/* current attempt counter */
$current = 0;
/* try to query */
while ($current++ <$MAX_ATTEMPS)
{
$result = mysql_query($sql);
if(!$result && ( mysql_errno== '1205' || mysql_errno == '1213' ) )
continue;
else
break;
}
}
Надеюсь, это может дать вам несколько хороших идей.
Я не знаю, какой код окружает эти примеры, но, возможно, стоит использовать LOCK IN SHARE MODE
для обоих потоков, поскольку вы фактически не обновляете саму строку. Если вы должны использовать LOCK FOR UPDATE
, я бы подумал, что блокировка другого потока будет единственным логическим путем.
Также, если вы готовы отказаться от MySQL, я обнаружил, что PostgreSQL имеет гораздо лучшее разрешение тупиковых ситуаций. В некоторых случаях я обнаруживал, что MySQL зависает каждый раз при запуске одного и того же скрипта в> 1 потоке. Если один и тот же сценарий в PostgreSQL может отлично справиться с любым количеством параллельных потоков.