Даже при использовании буферирования, что-то может пойти не так, хотелось. Если вы желаете защитить операции обновления и восстановить их из целой секции кода в виде единого целого, используйте транзакции.
Введение транзакций в ваше приложение предоставляет защиту вне буферирования записи и таблицы Visual FoxPro, путем размещения целой секции кода в защищенную и восстановливаемую единицу, действующую как единое целое. Вы можете вкладывать транзакции и использовать их для защиты буферированных обновлений. Транзакции Visual FoxPro доступно только для таблиц и представлений, содержащихся в контейнере базы данных.
Заключение сегментов кода в оболочки
Транзакции действуют, как оболочки, которые кэшируют операции обновлнения данных в памяти или на диске, до того, как применить их непосредственно к базе данных. Реальное обновление базы данных производится в конце транзакции. Если по какой-либо причине система не может произвести операцию обновления на базе данных, вы можете откатить целую транзакцию и операция обновления не будет произведена.
![]() |
---|
Операции буферированного обновления, производимые вне транзакции, игнорируются внутри транзакции в одной и той же сессии данных. |
Команды, которые управляют транзакциями
Visual FoxPro предоставляет три команды и одну функцию для управления транзакциями.
Для ... | используйте ... |
---|---|
начала транзакции |
|
определения текущего уровня транзакции |
|
сброса всех изменений, произведенных после самого последнего предложения BEGIN TRANSACTION |
|
блокировки записей, записи на диск всех изменений в таблицах в базе данных начиная с самой последней BEGIN TRANSACTION, а затем разблокировки записей |
Вы можете использовать транзакции для обертывания изменений в таблицах, структурных индексных (.cdx) и мемо файлах , связанных с таблицами внутри базы данных. Операции, включающие в себя переменные и другие объекты не признают транзакции; поэтому вы не можете откатить такие операции.
![]() |
---|
При использовании данных, хранящихся в удаленных таблицах, команды транзакий управляют только обновлениями данных в локальной копии курсора представления; обновления в удаленной базе данных не подвергаются их воздействию. Для того, чтобы разрешить ручные транзакции на удаленных таблицах используйте SQLSETPROP( ), а затем управляйте транзакцией с помощью функций SQLCOMMIT( ) и SQLROLLBACK( ). |
В общем случае, вы должны использовать транзакции скорее с буферами записей, чем с буферированием таблиц, за исключением обертки вызовов TABLEUPDATE(). Если вы помещаете в транзакцию команду TABLEUPDATE( ), вы можете откатить неудавшееся обновление, исследовать причину сбоя, а затем попытаться вызвать TABLEUPDATE() без потери данных. Это гарантирует обновление, случившееся в виде операции "все-или-ничего" ("all-or-nothing").
Хотя обработка простой транзакции обеспечивает безопасность операций обновления в нормальных ситуациях, она не обеспечивает глобальной защиты от системных сбоев. Если во время исполнения команды END TRANSACTION пропадет питание или случится иная неисправность системы, обновление данных может не состояться.
Используйте для транзакций приведенный шиблон кода:
![]() | |
---|---|
BEGIN TRANSACTION
* Обновление записей
IF lSuccess = .F. && произошла ошибка
ROLLBACK
ELSE && записывает изменения
* проверяет данные
IF && произошла ошибка
ROLLBACK
ELSE
END TRANSACTION
ENDIF
ENDIF |
К транзакциям применяются перечисленные ниже правила:
-
Транзакция начинается командой BEGIN TRANSACTION и заканчивается командой END TRANSACTION или ROLLBACK. Предложение END TRANSACTION без предшествовавшего ему BEGIN TRANSACTION сгенерирует ошибку.
-
Предложение ROLLBACK без предшествовавшего ему BEGIN TRANSACTION сгенерирует ошибку.
-
Начатая транзакция, остается в действии до тех пока, пока не начнется исполнение END TRANSACTION (или не будет выдана команда ROLLBACK ), даже с учетом исполнения программ или вызова функций, если не произошло прерывание исполнения приложения, которое вызовет откат.
-
Visual FoxPro использует данные, кэшированные в буфере транзакции до использования дисковых данных для запросов на данных, вовлеченных в транзакции. Это гарантирует использование самых свежих данных.
-
Если исполнение приложения прерывается во время транзакции, все операции откатываются.
-
Транзакции работают только на контейнере базы данных.
-
Вы не можете использовать команду INDEX, если она переписывает существующий индексный файл, или в случае, если открыт любой файл индекса (.cdx).
-
Транзакции принадлежат сессиям данных.
Транзакции показывают приведенное ниже поведение блокировки:
-
Внутри транзакции, Visual FoxPro накладывает блокировку во время прямых или косвенных вызовов команды. Любые системные команды или прямые или косвенные команды разблокировки кэшируются до момента завершения транзакции командами ROLLBACK или END TRANSACTION.
-
Если вы внутри транзакции используете команды блокировки, такие как FLOCK( ) или RLOCK( ), предложение END TRANSACTION не снимет установленную блокировку. А таком случае, вы должны явно разблокировать любые наложенные во время транзакции блокировки. Кроме того, вы должны обеспечить минимальное время, насколько это возможно, действия транзакции, содержащей команды FLOCK( ) или RLOCK( ); в противном случае, пользователь может быть заблокирован для доступа к данным на длительное время.
Вложение транзакций
Вложенные транзакции предоставляют логические группы операций обновления таблиц, которые изолированы от конкурентных процессов. Пары BEGIN TRANSACTION...END TRANSACTION не обязательно должны быть в одной и той же функции или процедуре. Приведенные ниже правила применяются ко вложенным транзакциям:
-
Вы можете иметь уровень вложенности до пяти пар BEGIN TRANSACTION...END TRANSACTION.
-
Обновления, произведенные во вложенных транзакциях не фиксируются до вызова внешней END TRANSACTION.
-
Во вложенных транзакциях END TRANSACTION работает только на транзакции, инициированной последней выданной BEGIN TRANSACTION.
-
Во вложенных транзакциях оператор ROLLBACK работает только на транзакции инициированной последней выданной BEGIN TRANSACTION.
-
Наиболее вложенное обновление в наборе вложенных транзакций на одних и тех же данных имеет преимущество над всеми остальными в том же самом блоке вложенных транзакций .
Уведомление в приведенном ниже примере вызвано тем, что так как изменения во вложенной транзакции не записаны на диск, а только в буфер транзакции, то внетренняя транзакция будет переписывать изменения, сделанные в том же самом поле STATUS поредшествующей транзакции:
![]() | |
---|---|
BEGIN TRANSACTION && транзакция 1
UPDATE EMPLOYEE ; && первое изменение
SET STATUS = "Contract" ;
WHERE EMPID BETWEEN 9001 AND 10000
BEGIN TRANSACTION && транзакция 2
UPDATE EMPLOYEE ;
SET STATUS = "Exempt" ;
WHERE HIREDATE > {^1998-01-01} && перепись
END TRANSACTION && transaction 2
END TRANSACTION && transaction 1 |
Приведенный ниже пример вложенной транзакции удаляет запись пользователя и все, связанные с ним счета. Транзакция будет откатана назад, если во время команды DELETE случится оишбка. Этот пример демонстрирует группирование операций обновления таблицы для защиты обновлений от частичного завершения и избежания конкурентных конфликтов.
Код | Комментарий |
---|---|
|
Очистка от других транзакций. |
|
Установка среды для буферизации. |
|
Разблокировка оптимистического буферирования таблицы. |
|
Изменение записи. Изменение другой записи. |
|
Запуск транзакции 1 и попытка обновить все измененные записи без force. |
|
Если обновление не случилось, откат тразакции. Получение ошибки из AERROR( ). Определение причины ошибки. Если траггер не удалось выполнить, то производится его обслуживание. Если поле не принимает null-значения, обслуживается этот случай. Если было нарушено правило поля, обслуживается этот случай. |
|
Если запись была изменена другим пользователем, ищется первая измененая запись. Поиск проводится через все измененные записи, начиная с первой записи. Блокировка каждой записи для гарантии, что вы можете произвести обновление. Проверка каждого поля на любое изменение. Проверка буферированного значения против значения на диске, а затем выдача сообщения пользователю. |
|
|
|
Если пользователь ответил "No," возврат одной записи к ее прежнему состоянию и ее разблокировка. |
|
Выход из цикла Break "FOR nField...". |
|
Получить следующую измененную запись. |
|
Запуск транзакции 2 и обновление всех не возвращенных к прежнему состоянию записей с force. Завершение транзакции 2. Снятие блокировки. |
|
Если запись используется другим пользователем, обрабатывается этот случай. Если нарушено правило поля, обрабатывается этот случай. Если была нарушена уникальной индекса, обрабатывается этот случай. В противном случае, пользователю выводится диалоговое окно. |
|
Завершение транзакции 1. |
Защита удаленных обновлений
Транзакции могут защитить вас от генерируемых системой ошибок во время обновления данных на удаленных таблицах. Приведенный ниже пример используется транзакции для обертывания операций записи данных на удаленной таблице.
Код | Комментарий |
---|---|
|
Получаем дескриптор соединения и разрешаем ручные транзакции. |
|
Начинаем ручную транзакцию. |
|
Пытаемся обновить все записи без force. Если не удалось, откатываем транзакицю на соединении для курсора. |
|
Получаем ошибку из AERROR( ). |
|
Если триггер не удалось выполнить, обрабатывается этот случай. |
|
Если поле не принимает null-значений, обрабатывается этот случай. |
|
Если нарушено правило поля, обрабатывается этот случай. |
|
Если запись была изменена друшим пользователем, обрабатывается этот случай. Осуществляется поиск через все измененные записи, начиная с первой. |
|
Проверяется каждое поле на любое изменение. Проверяется буферированное значение против значения на диске, а затем пользователю выводится сообщение. |
|
Если пользователь ответил "No," возврат одной записи к ее прежнему состоянию . Выход из цикла "FOR nField..." Получаем следующую измененную запись. |
|
Обновление всех не возвращенных к прежнему состоянию записей с force и выдача фиксации. |
|
Ошибка 109 указывает, что запись используется другим пользователем. |
|
Ошибка 1583 указывает, что было нарушено правило строки. |
|
Ошибка 1884 указывает, что была нарушена уникальность индекса. |
|
|
|
Пользователю выводится диалоговое окно. Конец обработки ошибок. |
|
Если все ошибки были обработаны и вся транзакция была осуществлена, выдается фиксация и завершение транзакции. |