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

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

Т1: SELECT SUM(BALANCE) FROM ACCOUNTS;

Т2: UPDATE ACCOUNTS SET BALANCE = BALANCE – 100 WHERE ACCNO = 3; UPDATE ACCOUNTS SET BALANCE = BALANCE + 100 WHERE ACCNO = 1;

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

  1. Т1 извлекает счет 1. Баланс равен 100. Вычисляемая сумма 100.

  2. Т2 извлекает счет 3. Баланс равен 100.

  3. Т1 извлекает счет 2. Баланс равен 100. Вычисляемая сумма 200.

  4. Т2 обновляет значение баланса счета 3. Оно становится равным 0.

  5. Т1 извлекает счет 3. Баланс равен 0. Сумма 200.

  6. Т2 извлекает счет 1. Баланс равен 100.

  7. Т1 извлекает счет 4. Баланс 100. Сумма 300.

  8. Т2 обновляет баланс счета 1, он становится равным 200.

Транзакция Т1 сообщит, что сумма балансов всех счетов равна 300, в то время как на самом деле она равна 400. Эта ситуация называется несогласованным анализом.

      1. Блокировки транзакций

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

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

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

Блокировка может налагаться либо автоматически, по инициативе СУБД (неявная блокировка), либо по команде, которая передается СУБД прикладной программой или запросом пользователя (явная блокировка).

Блокировки могут быть неполными. Если две транзакции просто считывают одно и то же множество данных, не производя никаких обновлений, им не нужно блокировать данные друг от друга. Поэтому существует два типа блокировок: совместная (shared, S) и исключающая (exclusive, X) .

Если доступ к объекту осуществляется только для чтения, то на него налагается совместная S-блокировка. Исключающая X-блокировка налагается на объект, который подвергается изменениям (обновляется или удаляется). Таким образом, действует следующий протокол:

  • Если на объект наложен S-блок, на него можно налагать другие S-блоки. Транзакция, которой требуется Х-блок, должна ожидать, пока будут сняты все S-блоки.

  • Если на объект наложен Х-блок, никакие другие блоки на него налагать нельзя. Все транзакции, которым требуется блок (X или S), должны ожидать, пока этот Х-блок будет снят.

Данный протокол означает, что при выполнении операции, включающей только чтение (например SQL-оператор SELECT), по отношению к этому объекту могут параллельно выполняться и другие подобные операции. При выполнении операции обновления другие операции выполняться не могут. Этот протокол позволяет избежать перечисленных выше проблем параллельной обработки. Потеря обновления исключается, поскольку транзакция Т1 заблокирует счет 1234, прежде чем приступить к обновлению, и транзакция Т2 не сможет начать выполнение своих обновлений до тех пор, пока Т1 не закончит свои. Удается также избежать зависимости от незафиксированных значений, так как до тех пор, пока Т1 не завершит откат, она будет блокировать счет 1234 (т.е. Т2 не сможет получить к нему доступ). Что касается несогласованного анализа, Т1 наложит на все считываемые записи счетов S-блок. Таким образом, Х-блок, запрашиваемый Т2, не будет предоставлен ей до тех пор, пока Т1 не завершит свой анализ.

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

Т1:

S-блок на объект 1

Т2:

S-блок на объект 1

S-блок на объект 2

Х-блок на объект 1

Х-блок на объект 1

S-блок на объект 2

Обе транзакции собираются запросить Х-блок на объект 1. Если Т1 – логически первая транзакция, тогда важно гарантировать, что она получит этот блок раньше, чем Т2. Предположим, что блокировки снимаются сразу же после того, как закончена соответствующая обработка объекта. Тогда при одновременной работе транзакций возможна такая последовательность событий:

  1. Т1 налагает S-блок на объект 1.

  2. Т2 налагает S-блок на объект 1.

  3. Т1 снимает S-блок с объекта 1 и налагает S-блок на объект 2.

  4. Т2 налагает Х-блок на объект 1 (она может это сделать, поскольку Т1 сняла свою S-блокировку с данного объекта).

  5. Т1 снимает S-блок с объекта 2. Теперь она должна ожидать предоставления Х-блока на объект 1.

  6. Т2 снимает Х-блок с объекта 1 и налагает S-блок на объект 2.

  7. Т1 налагает Х-блок на объект 1.

  8. Т2 снимает S-блок с объекта 2.

  9. Т1 снимает Х-блок с объекта 1.

В результате транзакция Т2 обновила объект 1 прежде, чем это сделала транзакция Т1. Такая последовательность действий ошибочна, поскольку Т1 – логически первая транзакция, т.е. ее результат должен быть зафиксирован в базе данных прежде, чем результат транзакции Т2. Рассматриваемое расписание событий противоречит принципу сериализации.

Принцип сериализации требует, чтобы при параллельном выполнении двух транзакций их результаты были такими же, как и в том случае, когда они выполняются строго последовательно, т.е. следующая транзакция не начинается до тех пор, пока предыдущая не завершится полностью. Таким образом, сериализация занимается рассмотрением конфликтующих запросов. В нашем примере конфликтующими запросами были запросы обеих транзакций на Х-блок объекта 1. График событий для определенного множества транзакций называется сериализуемым в случае, когда конфликтующие запросы в нем представлены в том же порядке, как если бы транзакции выполнялись последовательно. Другими словами, Х-блок на объект 1 должен запрашиваться транзакцией Т1 до того, как он запрашивается Т2.

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

В нашем сценарии Т1 не получит Х-блок на объект 1, если она к тому времени снимет S-блокировку с этого объекта, поэтому она ее не снимает. Следовательно, график событий будет таким.

  1. Т1 налагает S-блок на объект 1.

  2. Т2 налагает S-блок на объект 1.

  3. Т1 налагает S-блок на объект 2.

  4. Т2 запрашивает Х-блок на объект 1. Запрос отклоняется. Т2 ожидает.

  5. Т1 налагает Х-блок на объект 1.

  6. Т1 снимает все блоки.

  7. Т2 налагает Х-блок на объект 1.

  8. Т2 налагает S-блок на объект 2.

  9. Т2 снимает все блоки.

Протокол называется двухфазным потому, что все транзакции проходят две фазы: фазу получения и фазу снятия блокировок. В большинстве систем вторая фаза откладывается до самого конца транзакции, когда транзакция готова выполнить фиксацию или откат, и блокировки снимаются только в этот момент (как и в рассмотренном примере), хотя такие действия не всегда обязательны. В нашем сценарии, например, Т1 может снять S-блок с объекта 2 перед тем, как наложить Х-блокировку на объект 1. Однако, откладывая снятие блокировок до окончания транзакции, система избегает необходимости анализировать будущие требования блокировок.