Транзакции
Транзакции обеспечивают целостность данных в базе данных. Далее вы узнаете о неявных и явных транзакциях и о том, как инструкция UNDO отменяет транзакцию.
Неявные транзакции
Во время транзакции информация обо всех действиях базы данных, происходящих во время этой транзакции, записывается в файл предварительного образа (Before-Image или BI), связанный с базой данных. Файл BI находится на сервере вместе с другими файлами базы данных. Информация, записываемая в файл BI, согласовывается с синхронизацией данных, записываемых в фактические файлы базы данных. Таким образом, если во время транзакции возникает ошибка, AVM автоматически использует файл BI для восстановления базы данных до состояния, в котором она находилась до начала транзакции.
Операторы, запускающие неявную транзакцию:
- Блоки FOR, которые напрямую обновляют базу данных.
- Блоки REPEAT, которые напрямую обновляют базу данных.
- Блоки процедур, непосредственно обновляющие базу данных.
- Блоки DO с фразой ON ERROR, содержащие операторы, обновляющие базу данных.
Код в следующем примере запускает транзакцию для каждой итерации, что приводит к обновлению каждой записи клиента в отдельной транзакции.
FOR EACH Customer: /* Customer update block */ END.
Если приложение имеет несколько вложенных блоков, каждый из которых является транзакционным блоком, который существует сам по себе, то тогда самый внешний блок будет представлять собой транзакцию, а все вложенные транзакционные блоки внутри него становятся подтранзакциями. Вся активность базы данных, происходящая в пределах подтранзакции, записывается в файл локального предварительного образа перед (Local Before Image или LBI).
Блоком подтранзакций может быть:
- Блок процедуры, который запускается из блока транзакции в другой процедуре.
- Каждая итерация блока FOR EACH, вложенного в блок транзакции.
- Каждая итерация блока REPEAT, вложенного в блок транзакции.
- Каждая итерация DO TRANSACTION или DO ON ERROR внутри блока транзакции.
Если во время подтранзакции возникает ошибка приложения, вся работа, выполненная с начала подтранзакции, отменяется. Вы можете вкладывать подтранзакции в другие подтранзакции. Вы можете использовать эту инструкцию UNDO для программной отмены транзакции или подтранзакции.
Следующий пример кода запускает транзакцию на уровне таблицы Customer, а изменения выполняются в подтранзакции на уровне таблицы Order:
FOR EACH Customer: // Starts a transaction /* Customer update block */ FOR EACH Order WHERE Order.CustNum = Customer.CustNum: // Starts subtransaction /* Order update block */ END. END.
Явные транзакции
Вы также можете начать транзакцию, добавив ключевое слово TRANSACTION в блок DO, FOR, или REPEAT. Если ваш код запускает транзакцию в одной процедуре, а затем вызывает другую процедуру, внутреннюю или внешнюю, вся подпроцедура содержится в транзакции, которая была запущена до её вызова. Если подпроцедура запускает транзакцию, то она также должна завершиться внутри этой подпроцедуры, потому что начало и конец транзакции всегда являются началом и концом конкретного блока кода.
В следующем примере кода создаётся транзакция вокруг всех обновлений как в таблице Customer, так и в таблице Order:
DO TRANSACTION: DO: /* Customer update block */ END. FOR EACH Order WHERE Order.CustNum = Customer.CustNum: /* Order update block */ END. END. // TRANSACTION block
Оператор UNDO
Транзакция автоматически отменяется, когда возникает необработанная ошибка, которая выталкивает вас из блока транзакции. Логика вашего приложения также может отменить транзакцию, если вы обнаружите нарушение в своей бизнес-логике. Оператор UNDO позволяет контролировать, когда отменить действие транзакции самостоятельно. Это также позволяет вам определить, какую часть логики вашей процедуры нужно отменить.
Вы можете использовать ключевое слово UNDO как самостоятельный оператор. В этом случае AVM отменяет самый внутренний блок со свойством ошибки, которым может быть:
- Блок FOR
- Блок REPEAT
- Процедурный блок
- Блок DO с ключевым словом TRANSACTION или фразой ON ERROR
Базовый синтаксис оператора UNDO:
UNDO [ LEAVE | NEXT | RETRY | THROW error-or-stop-object-expression | RETURN [ ERROR | NO-APPLY ] [ return-value ] ] ]
В следующем примере кода транзакция запускается на уровне клиента, а изменения заказа выполняются в подтранзакции:
FOR EACH Customer: // Starts a transaction /* Customer update block */ FOR EACH Order WHERE Order.CustNum = Customer.CustNum: // Starts a subtransaction /* Order update block */ /* If validation fails, exit */ UNDO, LEAVE. // This undoes the subtransaction END. END.
Вы также можете указать UNDO в качестве опции блоков DO, FOR, или REPEAT. В следующем примере кода при обнаружении ошибки текущий блок отменяется, и выполнение возобновляется в коде, следующем за блоком.
DO TRANSACTION ON ERROR UNDO, LEAVE: DO: /* Customer update block */ END. FOR EACH Order WHERE Order.CustNum = Customer.CustNum: /* Order update block */ END. END. // TRANSACTION block
Вы также можете указать UNDO, LEAVE label, если при возникновении условия необходимо выйти из указанного транзакционного блока, идентифицированного меткой. Смотрите оператор LEAVE для получения более подробной информации об использовании меток.
Дополнительные сведения см. в «Управление транзакциями» и «Понимание концепции UNDO».