|
Программирование >> Oracle
Теперь оператор SELECT начинает выполняться и читать строку 1, строку 2 и так далее. В какой-то момент выполнения запроса некая транзакция переводит 400,00 $ со счета 123 на счет 987. Эта транзакция делает два изменения, но не фиксирует их. Таблица теперь выглядит следующим образом:
Итак, обе измененные строки заблокированы для изменения. В этом отношении все СУБД работают примерно одинаково. Различия появятся, когда запрос SELECT доберется до заблокированных данных. Добравшись до заблокированного блока, выполняемый запрос поймет , что данные в нем изменились после начала выполнения. Чтобы дать согласованный (правильный) ответ, сервер Oracle в этот момент восстановит блок с заблокированными данными в том виде, как он был на момент начала выполнения запроса. Таким образом, сервер Oracle обходит блокировку - он читает, восстанавливая соответствующие данные из сегмента отката. Согласованный и правильный ответ получается без ожидания фиксации транзакции. Однако СУБД, допускающая грязное чтение, просто вернет значение баланса счета 987 на момент его чтения, в данном случае 500 $. Запрос учтет перевод суммы 400 $ дважды и выдаст сумму, которая никогда не фигурировала в таблице счетов. В многопользовательской базе данных грязное чтение может быть опасным, и лично я никогда не видел от него пользы. В результате такого чтения не только выдается неверный результат, но могут в]даваться данные, никогда не существовавшие в базе данных. Пусть вместо перевода денег с другого счета транзакция добавила бы 400 $ на счет 987. Грязное чтение добавило бы 400 $ и в]дало правильный ответ, не так ли? А если не зафиксированная транзакция будет отменена? Нам только что предъявили 400 $, котор1х в базе данных фактически никогда не было. Дело в том, что грязное чтение - это не возможность, это просто лишняя ответственность. В Oracle брать ее на себя нет необходимости. Мы получаем все преимущества грязного чтения (отсутствие блокирования) без каких-либо некорректных результатов.
Уровень изолированности READ COMMITTED Уровень изолированности READ COMMITTED требует, чтобы транзакция читала только данные, зафиксированные до ее начала. Никаких грязных чтений. Неповторя-мость при чтении допускается (повторное чтение той же строки в транзакции может дать другой результат), как и чтение фантомов (по запросу могут возвращаться вновь вставленные строки, невидимые ранее для транзакции). READ COMMITTED, вероятно, - наиболее часто и повсеместно используемый в приложениях уровень изолированности транзакции. Другие уровни изолированности используются редко. Уровень READ COMMITTED не настолько безобиден, как можно судить по названию. Если взглянуть на представленную ранее таблицу, все кажется вполне очевидным. Естественно, с учетом указанных выше правил, запрос к базе данных, выполненный в транзакции с уровнем изолированности READ COMMITTED, должен выполняться одинаково, не так ли? Нет. Если запрос возвращает несколько строк, практически в любой СУБД уровень изолированности READ COMMITTED может стать причиной появления некорректных данных в той же мере, что и грязное чтение. В Oracle, благодаря использованию многовариантного доступа и согласованных по чтению запросов, результат запроса к таблице счетов при уровне изолированности READ COMMITTED будет таким же, как и в примере с READ UNCOMMITTED. Сервер Oracle восстанавливает измененные данные в том виде, какой они имели на момент начала выполнения запроса, возвращая ответ, соответствующий состоянию базы данных на тот же момент. Теперь давайте рассмотрим, как представленный выше пример мог бы выполняться в режиме READ COMMITTED в других СУБД. Результат удивит вас. Повторим тот же пример: Мы находимся в середине таблицы, прочитав и просуммировав к этому моменту N строк. Другая транзакция перевела 400 $ со счета 123 на счет 987. Эта транзакция еще не зафиксирована, поэтому строки 123 и 987 заблокированы. Мы знаем, как поведет себя СУБД Oracle, добравшись до счета 987: она прочитает измененные данные из сегмента отката, подсчитает баланс (значение окажется равным 100,00 $) и завершит запрос. Давайте рассмотрим, как другая СУБД, работающая в том же стандартном режиме READ COMMITTED, будет выдавать ответ. Время Запрос Транзакция по переводу со счета на счет Т5 Изменяет строку 342023, устанавливает на нее исключительную блокировку. В строке теперь значение 500 $. Тб Читает строку 342023, обнаруживает, что она была изменена. Сеанс блокируется в ожидании доступа к соответствующей строке. Выполнение запроса приостанавливается. Т7 Транзакция фиксируется. Т8 Читает строку 342023, находит в ней баланс 500 $ и выдает окончательный результат. Обратите внимание, что в другой СУБД запрос будет заблокирован, когда доберется до счета 987. Нашему сеансу придется ждать освобождения соответствующей строки, пока не зафиксируется транзакция, удерживающая исключительную блокировку. Это одна из причин появления у многих разработчиков плохой привычки фиксировать результаты в середине транзакции. В большинстве других СУБД изменения мешают чтению. Но самое печальное в этом то, что пользователь вынужден ожидать неверного результата. Как и в случае грязного чтения, получен результат, никогда не существовавший в базе данных, но в этом случае пришлось еще и ожидать. Важный урок здесь в том, что разные СУБД, выполняющие запрос с одним, предположительно безопасным, уровнем изолированности транзакции, возвращают существенно отличающиеся результаты в абсолютно одинаковых обстоятельствах. Важно понимать, что в Oracle не блокирующее чтение дается не ценой некорректности результатов. Оказывается, иногда можно, как говорится, и рыбку съесть, и на елку влезть. Уровень изолированности REPEATABLE READ Целью включения REPEATABLE READ в стандарт SQL92 б1ло обеспечение уровня изолированности транзакций, дающего согласованные, корректные результаты и предотвращающего потерю изменений. На двух примерах будет показано, как это достигается в Oracle и что происходит в других системах. Получение согласованного ответа При установке уровня изолированности REPEATABLE READ результаты запроса должны быть согласованными на определенный момент времени. Обычно СУБД (но не Oracle) достигают уровня REPEATABLE READ за счет установки строчн1х разделяемых блокировок чтения. Разделяемая блокировка чтения предотвращает изменение прочитанных данных другими сеансами. Это, несомненно, снижает параллелизм. В Oracle для получения согласованных по чтению результатов выбрана модель многовариантного доступа, обеспечивающая больший параллелизм.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |