Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции СУБД.doc
Скачиваний:
1
Добавлен:
01.07.2025
Размер:
6.32 Mб
Скачать

22.4.4 Проблема строк – призраков

На нижеследующем рисунке еще раз изображена схема работы программы для обработки заказов.

Рисунок 28 Проблема строк – призраков

На этот раз менеджер запустил программу генерации отчетов, которая просматривает таблицу ORDERS и печатает список заказов от клиентов какого-то сотрудника, подсчитывая их итоговую сумму. Тем временем этот сотрудник принимает дополнительный заказ на $5000. Заказ добавляется в базу данных, и транзакция завершается. Вскоре после этого менеджер по продажам снова просматривает таблицу ORDERS, выполняя тот же запрос, что и прежде. На этот раз в таблице имеется дополнительный заказ, а итоговая сумма заказов на $5000 больше, чем в результате первого запроса.

Здесь, как и в предыдущем примере, проблема заключается в несогласованности данных. Состояние базы данных соответствует реальной ситуации, и целостность данных не нарушена, но один и тот же запрос, выполненный дважды в течение одной транзакции, возвращает два различных результата. В предыдущем примере запрос извлекал одну строку, и противоречивость данных была вызвана выполнением инструкции UPDATE. Выполнение инструкции DELETE могло бы вызвать ту же проблему. В примере, представленном на нижеследующем рисунке, проблема возникла в результате выполнения инструкции INSERT. В первом запросе дополнительной строки не было, и после выполнения второго запроса сложилось такое впечатление, что она появилась “из ниоткуда”. Проблема строк-призраков, как и проблема несогласованных данных, может привести к противоречивым и неправильным расчетам. В стандарте SQL2 эта проблема обозначена как “РЗ”.

22.5.Параллельные транзакции

Как видно из приведенных примеров, при обновлении базы данных в многопользовательском режиме существует возможность нарушения ее целостности. Чтобы исключить такую возможность, в SQL используется механизм транзакций. Помимо того, что реляционная СУБД обязана выполнять транзакции по принципу “либо все, либо ничего”, она имеет и другое обязательство по отношению к транзакциям:

“В ходе выполнения транзакции пользователь видит полностью непротиворечивую базу данных. Он не должен видеть промежуточные результаты транзакций других пользователей, и даже завершение таких транзакций не должно отражаться на данных, которые пользователь видит в течение транзакции”.

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

“Когда две транзакции, A и B, выполняются параллельно, СУБД гарантирует, что результаты их выполнения будут точно такими же, как если бы вначале выполнялась транзакция А, а затем транзакция B; или вначале выполнялась транзакция B, а затем транзакция А”.

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

Однако тот факт, что СУБД изолирует пользователя от действий других пользователей, не означает, что о них можно забыть. Совсем наоборот. Поскольку другим пользователям также требуется обновлять базу данных параллельно с вами, ваши транзакции должны быть как можно более простыми и короткими, чтобы объем работы, выполняемой всеми, был больше.

Предположим, например, что вы запускаете программу, последовательно выполняющую три больших запроса на выборку. Так как программа не обновляет базу данных, может показаться, что нет необходимости использовать инструкцию COMMIT. Однако на самом деле программа должна выполнять эту инструкцию после каждого запроса, так как транзакция начинается автоматически вместе с первой инструкцией SQL в программе. Без инструкции COMMIT транзакция будет продолжаться до окончания программы. Кроме того, СУБД гарантирует, что данные, извлекаемые в течение транзакции, будут непротиворечивыми, и не будут зависеть от транзакции других пользователей. Это означает, что если ваша программа извлекла из базы данных определенную строку, то ни один пользователь, кроме вас, не сможет изменить эту строку до окончания вашей транзакции. Так происходит из-за того, что позднее в этой же транзакции вы можете снова извлечь ту же строку, а СУБД должна гарантировать, что в этой строке будут содержаться те же данные, что и при первой выборке. Поэтому, по мере того как ваша программа будет последовательно выполнять три запроса, другие пользователи не смогут изменять все большее количество данных.

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