Иллюстрированный самоучитель по SQL для начинающих

Защита данных

Уровни изоляции

Конечно, транзакция должна быть полностью изолирована от других транзакций, выполняющихся одновременно с вашей. Однако в многопользовательской системе из реального мира полная изоляция не всегда осуществима. Она может обернуться слишком высокой потерей производительности. И тут встает вопрос о компромиссе: какой уровень изоляции нужен вам на самом деле и какое количество производительности вы за него согласны отдать?

"Черновое" чтение

Самый слабый уровень изоляции называется READ UNCOMMITED и позволяет выполнять так называемое "черновое" чтение. При "черновом" чтении изменение, внесенное первым пользователем, может быть прочитано вторым пользователем еще до того, как первый пользователь подтвердит это изменение с помощью оператора COMMIT. Проблема возникает, если первый пользователь прерывает транзакцию и делает для нее откат. Все последующие действия второго пользователя выполняются теперь на основе неправильного значения. Приведем в качестве примера следующую ситуацию. Пусть имеется приложение, работающее с наличными товарами. Один пользователь уменьшает их количество, а второй читает новое, меньшее значение. Первый пользователь делает откат своей транзакции (восстанавливает первоначальное количество), но второй, думая, что товара осталось мало, заказывает его у поставщика, в результате на складе образуется товарный избыток. И это еще не худший случай.

Внимание:
Если вам нужны точные результаты, уровнем изоляции READ UNCOMMITED лучше не пользоваться
.

Уровень READ UNCOMMITED можно использовать тогда, когда нужно статистически обрабатывать такие малоизменяющиеся данные:

  • максимальная задержка в оформлении заказов;
  • средний возраст продавцов, не выполняющих норму;
  • средний возраст новых сотрудников.

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

Проблемы неповторяющегося чтения

Следующим, более высоким уровнем изоляции является READ COMMITED: изменение, производимое другой транзакцией, невидимо для вашей транзакции до тех пор, пока другой пользователь не завершит ее с помощью оператора COMMIT. Этот уровень обеспечивает лучший результат, чем READ UNCOMMITED, но он все-таки подвержен неповторяющемуся чтению – новой серьезной неприятности.

Для пояснения рассмотрим классический пример с наличными товарами. Пользователь 1 отправляет запрос в базу данных, чтобы узнать количество определенного товара, имеющееся на складе. Это количество равно десяти. Почти в то же самое время пользователь 2 начинает, а затем с помощью оператора COMMIT завершает транзакцию, которая записывает заказ на десять единиц того же товара, уменьшая, таким образом, его запасы до нуля. И тут пользователь 1, думая, что в наличии имеется десять единиц товара, пытается оформить заказ на пять единиц. Но и такого количества уже нет. Пользователь 2, по существу, опустошил склад. Первоначальная операция чтения, выполненная пользователем 1 по имеющемуся количеству, является неповторяющейся. Это количество изменили прямо под носом пользователя 1, и все предположения, сделанные на основе полученных им данных, являются неправильными.

Риск фиктивного чтения

Уровень изоляции REPEATABLE READ дает гарантию, что такой неприятности, как неповторяющееся чтение, уже не будет. Однако на этом уровне все равно часто происходит фиктивное чтение – неприятность, возникающая тогда, когда данные, читаемые пользователем, меняются в результате другой транзакции, причем меняются как раз во время чтения.

Предположим, например, что пользователь 1 отправляет на выполнение команду, условие поиска которой (предложение WHERE или HAVING) выбирает какое-либо множество строк. И сразу же после этого пользователь 2 выполняет, а затем с помощью оператора COMMIT завершает операцию, в результате которой данные, хранящиеся в одной из этих строк, становятся другими. Вначале эти данные удовлетворяли условию поиска, заданному пользователем 1, а теперь – нет. Или, возможно, некоторые строки, которые вначале этому условию не соответствовали, теперь вполне для него подходят. А пользователь 1, транзакция которого еще не завершена, и понятия не имеет об этих изменениях; само же приложение ведет себя так, как будто ничего не произошло. И вот несчастный пользователь 1 оправляет на выполнение еще один оператор SQL. В нем условия поиска те же самые, что и в первоначальном операторе, поэтому пользователь надеется, что получит те же строки, что и перед этим. Но вторая операция выполняется уже не с теми строками, что первая. В результате фиктивного чтения надежная информация оказалась негодной.

Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.