Завершение транзакций
Завершение транзакций
Транзакция завершается, когда клиентское приложение подтверждает ее или отменяет. Если оператор COMMIT или вызов эквивалентной функции API isc_commit_ transaction не будут успешными, то транзакция не будет подтверждена. Если транзакция, которая не может быть подтверждена, не будет отменена явным вызовом клиентом ROLLBACK (ИЛИ функцией API isc_roiiback_transaction), транзакция не будет отменена. Эти операторы не являются силлогизмом. Ошибки при завершении транзакций являются весьма общей проблемой, часто обсуждаемой в публичных конференциях!
Оператор COMMIT
Синтаксис оператора COMMIT:
COMMIT [WORK] [RETAIN [SNAPSHOT]];
Простой COMMIT - иногда называемый жестким подтверждением по причинам, которые станут понятными, - делает изменения, отправленные в базы данных, постоянными и освобождает все физические ресурсы, связанные с транзакцией. Если по различным причинам COMMIT завершается с ошибкой и возвращает клиенту исключение, транзакция остается в неподтвержденном состоянии. Клиентское приложение должно обработать ошибку подтверждения транзакции, выполнив ее явный откат или, если это возможно, исправив ошибку и заново выполнив оператор.
COMMIT с режимом RETAIN
Необязательное расширение RETAIN [SNAPSHOT] оператора COMMIT приводит к тому, что сервер сохраняет "образ" контекста физической транзакции и производит запуск новой транзакции как клона подтвержденной транзакции. Если это так называемое мягкое подтверждение используется в транзакциях SNAPSHOT или SNAPSHOT TABLE STABILITY, клонируемая транзакция при своем запуске сохраняет тот же образ данных, что и исходная транзакция.
Хотя это приводит к постоянному подтверждению работы и, следовательно, изменяет состояние базы данных, COMMIT RETAIN (CommitRetaining) не освобождает ресурсы. На отрезке жизни логической задачи, которая включает в себя множество повторений похожих операций, клонирование контекста уменьшает некоторые накладные расходы, которые могли бы возникнуть при освобождении ресурсов каждый раз при COMMIT; при этом сначала лишь выделяются идентичные ресурсы при старте новой транзакции. В частности, это сохраняет "открытые" в настоящий момент курсоры для выбранных наборов.
Тот же самый идентификатор транзакции остается активным в TSB и никогда не становится "подтвержденным". По этой причине такое действие часто называется мягким подтверждением (soft commit) по сравнению с "жестким" подтверждением, выполняемым немодифицированным оператором COMMIT.
Каждое мягкое подтверждение похоже на точку сохранения без возможности возврата к ней. Все последующие операторы ROLLBACK отменяют только те изменения, которые были отправлены на сервер после последнего мягкого подтверждения.
Преимущество мягкого подтверждения в том, что оно облегчает жизнь программиста, особенно тех, кто использует компоненты, которые реализуют поведение "прокручиваемой базы данных". Это было сделано для поддержки сетки данных (grid) в пользовательском интерфейсе, используемой многими пользователями среды разработки Borland Delphi (и C++ Builder). Сохраняя контекст транзакции, приложение может отображать плавный переход состояния до-и-после, что сокращает работу программиста, которому иначе пришлось бы стартовать новые транзакции, открывать новые курсоры и заново синхронизировать их с наборами строк, хранящимися на клиенте.
Различные реализации доступа к данным часто объединяют пересылку на сервер единичного изменения, добавления или удаления с немедленным COMMIT RETAIN В механизм, дублирующий "автоподтверждение". Общим для уровней интерфейса является реализация возможности автоподтверждения для "молчаливого" управления транзакцией, запуская транзакцию невидимо для программиста в ситуациях, когда написанный программистом код пытается передавать оператор без предварительного старта транзакции.
Явное управление транзакциями стоит дополнительных усилий, особенно если вы применяете продукт, использующий такие гибкие средства, которые предоставляет Firebird. В загруженном работой окружении вариант COMMIT RETAIN может сократить время выполнения и ресурсы, однако он имеет некоторые серьезные недостатки.
* Транзакция SNAPSHOT продолжает хранить первоначальный образ базы данных, что означает, что пользователь не видит подтвержденных результатов других транзакций, которые ожидали подтверждения при старте текущей транзакции.
* Пока та же транзакция продолжает выполнять подтверждение в варианте RETAIN, ресурсы, используемые на сервере, не освобождаются, что приводит к чрезмерному росту ресурсов памяти, потребляемых TSB. Этот рост сильно ухудшает производительность, в конечном счете "замораживая" сервер, и при неблагоприятных условиях операционной системы даже может привести к краху системы.
* Никакие старые версии записей, ставшие устаревшими в результате операций, подтвержденных в транзакциях COMMIT RETAIN, не могут быть включены в сборку мусора, т. к. исходная транзакция никогда не выполняет "жесткого подтверждения".
Оператор ROLLBACK
Как и COMMIT, оператор ROLLBACK освобождает ресурсы на сервере и завершает физический контекст транзакции. При этом вид состояния базы данных в приложении возвращается к тому виду, как если бы эта транзакция никогда не стартовала. В отличие от COMMIT данный оператор никогда не завершается с ошибкой.
В логическом контексте "задачи" клиента после отката транзакции ваше приложение должно предоставить пользователю средства для разрешения проблем, которые вызвали исключение, и для повторного запуска новой транзакции.
RollbackRetaining
SQL в Firebird не реализует синтаксис RETAIN В ROLLBACK так же, как это делается в COMMIT. При этом похожий механизм клонирования реализован в функции API isc_roiiback_retaining(). Она восстанавливает для приложения вид базы данных в то состояние, которое было, когда транзакция получила дескриптор или, в случае транзакции READ COMMITTED, в то состояние, которое было при последнем вызове
isc_roiiback_retaining(). Выделенные для транзакции системные ресурсы не освобождаются, курсоры сохраняются.
ROLLBACK RETAIN имеет те же самые ловушки, что и COMMIT RETAIN - и даже больше. Поскольку отдельные вызовы откатов производятся в ответ на исключение некоторого вида, сохранение контекста транзакции также сохранит и причины исключения. ROLLBACK RETAIN не должен использоваться в тех случаях, если существует шанс, что ваш последующий код обработки исключения не найдет и не исправит наследуемое исключение. Любые последующие ошибки ROLLBACK RETAIN должны обрабатываться с полным откатом транзакции для освобождения ресурсов и устранения проблемы.