Минимальный уровень изоляции транзакций, чтобы избежать " потерянных обновлений"

с уровнями изоляции транзакций SQL Server вы можете избежать некоторых нежелательных проблем параллелизма, таких как грязные чтения и т. д.

тот, который меня сейчас интересует, это потерянные обновления - тот факт, что две транзакции могут перезаписывать обновления друг друга, никто этого не замечает. Я вижу и слышу противоречивые утверждения о том, какой уровень изоляции, как минимум, я должен выбрать, чтобы избежать этого.

Кален Делани в своей книге " внутренние компоненты SQL Server говорит (Глава 10 - транзакции и параллелизм - страница 592):

в Read Uncommitted isolation все поведение, описанное ранее,кроме потерянных обновлений, возможно.

с другой стороны, независимый тренер SQL Server, дающий нам класс, сказал нам, что нам нужно хотя бы "повторяемое чтение", чтобы избежать потерянных обновлений.

Так кто прав?? И почему??

5 ответов


пример в книге-Клерк A и Клерк B, получающий отгрузки виджетов.

они оба проверяют текущий инвентарь, см. 25 на складе. У клерка A есть 50 виджетов и обновления до 75, у Клерка B есть 20 виджетов и поэтому обновления до 45 перезаписывают предыдущее обновление.

Я предполагаю, что она имела в виду, что этого явления можно избежать на всех уровнях изоляции клерком

UPDATE Widgets
SET StockLevel = StockLevel + 50
WHERE ...

и Клерк Б делает

UPDATE Widgets
SET StockLevel = StockLevel + 20
WHERE ...

конечно, если SELECT и UPDATE выполняются как отдельные операции вам понадобится repeatable read чтобы избежать этого так S блокировка строки удерживается на протяжении транзакции (что приведет к взаимоблокировке в этом сценарии)


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

Microsoft Technet

в частности, этот абзац:

Потерянного Обновления

потерянное обновление можно интерпретировать одним из двух способов. В первом сценарии потерянное обновление считается произошедшим, когда данные, которые обновление одной транзакцией перезаписывается другой транзакцией до фиксации или отката первой транзакции. этот тип потерянного обновления не может произойти в SQL Server 2005, поскольку он не разрешен на любом уровне изоляции транзакций.

другая интерпретация потерянного обновления - это когда одна транзакция (транзакция № 1) считывает данные в свою локальную память, а затем другая транзакция (транзакция № 2) изменяет эти данные и совершает свое изменение. После этого транзакция №1 обновляет те же данные на основе того, что она считала в память до выполнения транзакции № 2. В этом случае обновление, выполненное транзакцией № 2, можно считать потерянным обновлением.

Итак, по сути, оба человека правы.

лично (и я открыт для того, чтобы ошибаться, поэтому, пожалуйста, исправьте меня, поскольку я только учусь этому) я беру из этого следующие два момента:

  1. весь смысл a среда транзакций предназначена для предотвращения потерянных обновлений, как описано в верхнем абзаце. Поэтому, если даже самый базовый уровень транзакции не может этого сделать, зачем его использовать.

  2. когда люди говорят о потерянных обновлениях, они знают, что первый абзац применяется, и поэтому, вообще говоря, означает второй тип потерянного обновления.

еще раз, пожалуйста, поправьте меня, если что-то здесь не так, как я хотел бы тоже разобраться в этом.


потерянные обновления могут произойти, даже если чтение и запись находятся в отдельных транзакциях, например, когда пользователи читают данные на веб-страницах, а затем обновляют. В таких случаях уровень изоляции не может защитить вас, особенно при повторном использовании соединений из пула соединений. Мы должны использовать другие подходы, такие как rowversion. вот мой законсервированный ответ.


мой опыт заключается в том, что с Read Uncommitted вы больше не получаете "потерянные обновления", однако вы можете получить "потерянные откаты". Тренер SQL, вероятно, имел в виду эту проблему параллелизма, поэтому ответ, который вы, вероятно, ищете,Repeatable Read.

тем не менее, мне было бы очень интересно, если у кого-то есть опыт, который идет против этого.


Как отметил Фрэнсис Роджерс, вы можете положиться на реализацию SQL Server, что после того, как транзакция обновила некоторые данные, каждый уровень изоляции всегда выдает "блокировки обновления" над данными и отрицает обновления и записи из другой транзакции, независимо от уровня изоляции. Вы можете быть уверены, что этот вид потерянных обновлений покрыты.

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

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