Выбрать главу

Контекст транзакции

Завершенное общение между клиентом и сервером называется транзакцией. Каждая транзакция имеет уникальный контекст, что приводит к тому, что транзакция будет изолирована от всех других транзакций указанным способом. Правила для контекста транзакции задаются в программе клиентского приложения, при передаче параметров транзакции. Транзакция стартует, когда клиент сообщает серверу о ее начале, получая с сервера дескриптор транзакции. Она остается активной, пока клиент не подтвердит работу (если это возможно) или не отменит ее.

Одна транзакция, много запросов

В Firebird любая операция, запрашиваемая клиентом, должна появиться в контексте какой-либо активной транзакции. Одна транзакция в своих границах может включать один или много клиентских запросов и ответов сервера. Одна транзакция может использовать более одной базы данных, осуществляя операции чтения и записи во многих базах данных в процессе решения задачи. Задачи, создающие базы данных или изменяющие их физическую структуру (одиночный оператор DDL или пакет таких операторов), также используют транзакции. Клиент и сервер имеют свои роли.

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

Одно клиентское соединение может иметь много активных транзакций.

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

соответствующим образом обрабатывались конфликты и предотвращалось нарушение согласованности базы данных.

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

Рис. 25.1. Контекст транзакции и независимость

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

Атомарность модели

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

Транзакции и MGA

MGA (Multi-Generational Architecture, многоверсионная архитектура) является названием основной архитектурной модели управления состоянием базы данных Firebird.

В модели MGA каждая строка, сохраняемая в базе данных, содержит уникальный идентификатор той транзакции, которая ее сохранила. Если другая транзакция посылает изменение строки, сервер записывает на диск новую версию этой строки с новым идентификатором транзакции и преобразует образ старой версии в ссылку (называемую дельтой) на эту новую версию. Теперь сервер содержит два "поколения" одной и той же строки.

Пересылка в сравнении с COMMIT

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

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

! ! !

ПРИМЕЧАНИЕ. Вызовы клиентом COMMIT или ROLLBACK являются единственно возможными способами завершения транзакции, Ошибки при подтверждении не означают, что сервер выполнит откат транзакции.

. ! .

Откат

Откат (rollback) никогда не завершается с ошибкой. Он отменит все изменения, которые были запрошены в процессе выполнения транзакции, - изменения, которые привели к исключениям, так же как и изменения, которые были успешными и не вызвали исключения.

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

Блокировка строки

В MGA наличие ожидающих завершения новых версий строки имеет следствием блокировку строки. При большинстве условий наличие новой подтвержденной версии блокирует запрос на изменение или удаление этой строки - это конфликт блокировки.

При получении запроса на изменение или удаление сервер проверяет состояние каждой транзакции, которая "владеет" новыми версиями строки. Если самая новая из этих владеющих транзакций является активной или была подтверждена, сервер отвечает запрашивающей транзакции в соответствии с ее контекстом (уровень изоляции и параметры разрешения блокировки).

Если транзакция самой новой версии является активной, запрашивающая транзакция по умолчанию будет ожидать ее завершения (подтверждения или отката), а затем сервер позволит ей продолжить свое выполнение. При этом если было задано NOWAIT, сервер вернет исключение конфликта запрашивающей транзакции.

Если транзакция самой новой версии подтверждена и запрашивающая транзакция имеет уровень изоляции SNAPSHOT (т. е. параллельный), сервер отвергает запрос и сообщает о конфликте блокировки. Если транзакция имеет уровень изоляции READ COMMITTED с установленным по умолчанию значением RECORD_VERSION, сервер выполняет запрос и записывает новую версию записи с идентификатором этой транзакции.

! ! !

ПРИМЕЧАНИЕ. Возможны другие условия, когда запрашивающая транзакция имеет уровень изоляции READ COMMITTED. На результат любого запроса транзакции могут также воздействовать необычные условия в контексте транзакции, которая владеет ожидающими завершения изменениями. Более подробную информацию об этих вариантах см. в главе 26, где детально рассматриваются параметры транзакции.

. ! .

Firebird не использует традиционную двухфазную блокировку для большинства обычных контекстов транзакции. Следовательно, все нормальные блокировки выполняются на уровне строки (такая блокировка называется оптимистической) - каждая строка доступна всем транзакциям чтения/записи, за исключением транзакции, выполняющей создание новой версии этой строки.

вернуться

89

Программисты API. смотрите в TP В константу isc_tpb_no_auto_undo.