2016-02-21 3 views
2

Сценарий:Как предотвратить взаимоблокировки базы данных в параллельных транзакциях?

транзакция А начинает ...

START TRANSACTION; 
UPDATE table_name SET column_name=column_name+1 WHERE id = 1 LIMIT 1; 

В то же время, сделка B начинается ...

START TRANSACTION; 
UPDATE table_name SET column_name=column_name+1 WHERE id = 2 LIMIT 1; 
UPDATE table_name SET column_name=column_name-1 WHERE id = 1 LIMIT 1; 
COMMIT; 

прямо сейчас, транзакция B ожидает строка 1, которая заблокирована в транзакции A.

И транзакция продолжается ...

UPDATE table_name SET column_name=column_name-1 WHERE id = 2 LIMIT 1; 
COMMIT; 

И теперь у нас есть мертвый замок, так что оба транзакции ожидают друг от друга, чтобы разблокировать строку, что они хотят, чтобы обновить: '(

Как я спросил в заголовке, как мы можем предотвратить взаимоблокировки в транзакции РСУБД?

Я думаю, что единственный способ исправить эту ситуацию - это откат транзакции B и ее повторное выполнение. Но как мы можем узнать, что мы находимся в тупике, и немедленно выходим из него, и как мы можем гарантировать, что мы не имеем запас и бесконечный цикл (например, в очень тяжелых веб-приложениях).

Если это необходимо, я использую MySQL. Но любое решение для других RDBMSs приветствуется - для помощи другим людям, приезжающим сюда из Google :)

+0

Вы не можете предотвратить взаимоблокировки, однако вы можете написать код, который минимизирует их происхождение. – Shadow

+1

@trincot Я думаю, что это транзакция A блокирует строку # 1, транзакция B блокирует строку №2 и ждет транзакции A, чтобы разблокировать строку # 1, а транзакция A ждет транзакции B, чтобы разблокировать строку №2, поэтому обе транзакции ждут друг для друга. Можете ли вы исправить меня, если я ошибаюсь? Благодарю. – user5483434

+1

@Shadow Можете ли вы сообщить мне, как я могу свести к минимуму их присутствие? – user5483434

ответ

2

Большинство баз данных (если не все) автоматически обнаруживают тупик, выбирают один сеанс, чтобы быть жертвой, и автоматически откатывают этот сеанс транзакции для выхода из тупика. Например, здесь представлена ​​документация MySQL deadlock detection and rollback.

Тупиковые ошибки - это ошибки программирования. Одним из простых решений для предотвращения взаимоблокировок является обеспечение того, чтобы вы всегда фиксировали строки в определенном порядке. Например, если у вас есть транзакция, которая хочет обновить две разные строки, всегда обновляйте строку с меньшим размером id и большим id секунд. Если ваш код всегда это делает, у вас, по крайней мере, не будет блокировок на уровне строк. Помимо этого, внедрите соответствующую сериализацию для критических разделов в вашем коде. Что именно, что влечет за собой, очень зависит от вашего приложения.

+0

Спасибо, Джастин. На самом деле я услышал мертвую блокировку в [этом вопросе] (http://stackoverflow.com/questions/35525208/is-it-ok-to-run-whole-php-application-in-a-mysql-transaction?noredirect1 # comment58747603_35525208) (что я спросил несколько часов назад). Можете ли вы помочь мне в тупиках на уровне строк? Существуют ли какие-либо другие взаимоблокировки в InnoDB? (на уровне таблицы? любой другой?) Кроме того, английский не является моим родным языком, не могли бы вы объяснить, что вы подразумеваете под «осуществить соответствующую сериализацию для критических разделов в вашем коде», пожалуйста? Теперь я прочитаю связанный URL. Еще раз спасибо. – user5483434

+0

@ user5483434 - Подавляющее большинство тупиков - это блокировки уровня строки, но есть и любое количество других ресурсов, которые вы могли бы заблокировать, что может привести к тупиковой ситуации. Если вы ищете «параллельный тупик программирования», есть (много) книг по параллельному программированию и подходы к реализации соответствующей сериализации. Это не то, что реально можно охватить в таком форуме. И, как я уже сказал, именно то, что влечет за собой, сильно зависит от вашего приложения. –