Чтобы избежать взаимных блокировок, одна из наиболее распространенных рекомендаций - «получить блокировки в том же порядке» или «получить доступ к объектам в том же порядке». Очевидно, это имеет смысл, но всегда ли это возможно? Это всегда возможно? Я продолжаю сталкиваться со случаями, когда я не могу следовать этому совету.
Если я храню объект в одной родительской таблице и в одной или нескольких дочерних, я вообще не могу следовать этому совету. При вставке мне нужно сначала вставить родительскую строку. При удалении я должен сделать это в обратном порядке.
Если я использую команды, которые касаются нескольких таблиц или нескольких строк в одной таблице, то, как правило, я не контролирую, в каком порядке создаются блокировки (при условии, что я не использую подсказки).
Таким образом, во многих случаях попытка получить блокировки в одном и том же порядке не предотвращает все тупики. Итак, нам все равно нужна какая-то обработка тупиков - мы не можем предполагать, что сможем устранить их все. Если, конечно, мы не сериализуем весь доступ с помощью Service Broker или sp_getapplock.
Когда мы повторяем попытки после взаимоблокировок, мы, скорее всего, перезапишем изменения других процессов. Нам нужно знать, что очень вероятно, что кто-то еще изменил данные, которые мы намеревались изменить. Особенно, если все читатели работают в режиме изоляции моментальных снимков, тогда читатели не могут быть вовлечены в взаимоблокировки, что означает, что все стороны, вовлеченные в тупик, являются авторами, которые модифицировали или пытались изменить одни и те же данные. Если мы просто перехватываем исключение и автоматически повторяем попытку, мы можем перезаписать чужие изменения.
Это называется потерянными обновлениями, и обычно это неправильно. Как правило, правильное решение после тупика - повторить попытку на более высоком уровне - повторно выбрать данные и решить, сохранять ли таким же образом, как было принято первоначальное решение о сохранении.
Например, если пользователь нажал кнопку «Сохранить» и транзакция сохранения была выбрана в качестве жертвы взаимоблокировки, возможно, было бы неплохо повторно отобразить данные на экране после тупика.