Template:Транзакции

From SunFlurry wiki
Jump to: navigation, search

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

К примеру, при изменении и обработке одного документа, должен быть также изменен и обработан связанный с ним второй документ. Без применения транзакции, может возникнуть ситуация, когда изменения первого документа уже сохранены в базу данных и из-за ошибки, сбоя сети, или остановки программы пользователем, изменения второго документа не будут сохранены, таким образом нарушается согласованность документов. При применении транзакции, она должна начаться до сохранения изменений в первый документ и закончиться (CommitTransaction) после сохранения изменений во второй документ. Если выполнение программы будет прервано после записи в первый документ, сервер базы данных автоматически выполнит отмену транзакции (RollbackTransaction), так как она не была зафиксирована, все изменения будут отменены, и документы останутся в согласованном состоянии.

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

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

  • Транзакция всегда должна быть заключена внутрь конструкций Try ... Except EndTry, либо Try ... Finally EndTry, при любой ошибке в теле конструкции Try, транзакцию необходимо отменить.
  • Сервер базы данных имеет счетчик транзакций, если клиент выполнит инструкцию BeginTransaction несколько раз подряд, этот счетчик будет увеличен соответствующее количество раз. После этого, для фиксирования транзакции необходимо выполнить такое же количество операций CommitTransaction, только после этого транзакция будет зафиксирована. Это позволяет использовать целые рабочие блоки с транзакциями внутри обработок, которые также используют транзакции. Важно, однако, понимать, что любая ошибка БД внутри транзакции (к примеру, невозможность сохранения элемента, так как он занят, невозможно обработать документ и т.д.), либо единственная операция RollbackTransaction отменяет сразу все уровни транзакции. Блоки, использующие транзакцию, вызывающие функции, использующие транзакцию, должны иметь проверку, не произошла ли отмена транзакции внутри вызываемой функции.
  • При прерывании транзакции пользователем, закрытии программы, потери связи с сервером и пр. во время транзакции, сервер автоматически вызовет отмену незавершенной транзакции.
  • Транзактные изменения обычно прозрачны, поэтому, другие пользователи будут видеть произведенные изменения по мере их появления до фиксирования транзакции. Если необходимо исключить работу пользователей с несогласованной информацией, все объекты, участвующие в транзакции должны быть заблокированы до начала проведения изменений.
  • Отмена изменений транзакции (RollbackTransaction) отменяет произведенные изменения только в базе данных. Текущие объекты в памяти системы останутся измененными и не примут состояние, в котором они были до начала транзакции. Особенно это опасно для объектов, которые открыты для редактирования в визуальном режиме. Если пользователь пытался сохранить элемент справочника, при этом внутри модуля сохранения программа создала ряд изменений в реквизитах этого элемента, однако, сохранение было отменено по какой-то причине, в базе данных будет находиться объект без этого ряда изменений, однако, визуальный объект будет содержать все сделанные изменения. Для того, чтобы избежать появления таких устаревших объектов, необходимо либо перечитать объект из базы данных после отмены транзакции (см. Reload), либо (особенно важно для визуальных объектов), сохранить состояние объекта до начала транзакции с помощью функции StoreObjectToBuffer и вернуть его в исходное состояние, если транзакция была отменена с помощью функции RestoreObjectFromBuffer. При обработке документов в стандартном режиме (параметр AutoTransactionMode включен), система автоматически использует StoreObjectToBuffer до начала транзакции и восстанавливает состояние объекта с помощью RestoreObjectFromBuffer, если обработка была отменена.
  • Создаваемые новые объекты внутри транзакции (если они были сохранены) нужно утилизировать (очистить переменную), если транзакция была отменена. После отмены транзакции в переменной находится объект, который отсутствует в базе данных, он имеет свой внутренний код базы данных, однако, этот код неверен, так как произошла отмена транзакции, и объекта с таким кодом больше нет. Если сохранить этот объект в какой-либо реквизит другого объекта, система не сможет обнаружить его ошибочность. Когда позже в базу данных будут добавлены другие новые объекты такого же типа и вида, один из новых объектов получит внутренний код, которым обладал исходный несуществующий в базе данных объект. Возникнет ситуация, когда реквизит будет содержать ссылку на новый объект, не участвовавший в изначальной транзакции.
  • Внутри транзакции (BeginTransaction), любые изменения в накопителях типа ClearStorages, SaveStorage автоматически произведут блокировку изменяемых накопителей (как будто была вызвана функция LockStorage). Функции CommitTransaction и RollbackTransaction, а также любая ошибка или завершение выполнения модуля, автоматически разблокируют все накопители, заблокированные за время транзакции. В этом случае нет необходимости в вызове функции UnlockStorage.