База данных IsolationLevel и проблема чтения и записи - PullRequest
2 голосов
/ 25 июня 2019

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

Конкретный сценарий описан ниже

  1. process1 читает начальное состояние: ReadyForShipment
  2. process2 читает состояние: ReadyForShipment
  3. process1 изменяет состояние на «Отменено» и фиксирует свою транзакцию
  4. process2 изменяет состояние на «Отправлено», что недопустимо, поскольку отмененный элемент не должен быть отправлен.

Prcess1 и process2 не взаимодействуют друг с другом, и я надеюсь, что решение на уровне базы данных сохранит это.Я знаю, что уровень изоляции Serializable решает проблему, потому что блокировка чтения, полученная на шаге 2, препятствует выполнению шага 3.

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

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

Кажется, подразумевается, что управление версиями строк может быть решением для чтенияи напиши проблему.На шаге 4 при управлении версиями строк база данных должна быть в состоянии обнаружить, что она пытается изменить строку, версия которой уже была изменена с момента чтения на шаге 2.Но мой эксперимент доказал, что это не поведение.С изоляцией ReadCommited и READ_COMMITTED_SNAPSHO базы данных, для которой установлено значение ON, шаг 4 завершился успешно с обновленным состоянием Shipped.

Мой вопрос, помимо уровня Serializable, существует ли еще одно решение проблемы уровня чтения и записи, описанное выше, на уровне базы данных

1 Ответ

1 голос
/ 25 июня 2019

Что делает управление версиями строк в SQL-сервере (это эквивалентно тому, как работает многоуровневый контроль параллелизма MVCC в других базах данных) - для каждой измененной строки он поддерживает отдельную версию, так что, если есть запрос на чтение для этой строки, - эта версия используется вместо ссылки на еще не принятую строку. Это лучший способ реализовать параллелизм, так как чтение, тогда не требует блокировки, и поэтому применяется во всех основных базах данных. Теперь вы можете понять, почему использование управления версиями строк (с согласованностью чтения на уровне операторов или на уровне транзакции) дает только гарантию согласованного чтения (использование версии данных до того, как изменение началось в результате еще не совершенной транзакции).

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

Другим решением будет использование оптимистичного управления параллелизмом с использованием столбца версии в таблице. Более поздняя транзакция будет иметь «где версия = 1» в предложении обновления, которое вернет 0 обновленных строк, так как версия уже была увеличена до 2 первой транзакцией. Это может рассматриваться как логическая ошибка на стороне приложения, и сообщение распространяется соответствующим образом.

...