Управление экземплярами
Чтобы получить общую информацию и взглянуть на примеры использования, см. раздел Управление транзакциями.
Соблюдайте следующие правила в работе с транзакциями:
Правило #1
Запросы в транзакции должны отправляться на сервер в виде единого блока. Недостаточно просто размещать их между началом транзакции и коммитом или откатом. Чтобы убедиться, что они отправляются в виде единого блока: поместите их в функцию, поместите их на одну строку или используйте символы-разделители, чтобы многостроковые запросы обрабатывались совместно.
Правило #2
Все операции с базой данных в рамках транзакции должны работать с одним движком баз данных. Небезопасно в рамках одной транзакции получать доступ к наборам кортежей, которые определяются по {engine='vinyl'}
, а также к наборам кортежей, которые определяются по {engine='memtx'}
.
Правило #3
Requests which cause changes to the data definition
– create, alter, drop, truncate – are only allowed with
Tarantool version 2.1 or later.
Data-definition requests which change an index
or change a format, such as
space_object:create_index() and
space_object:format(),
are not allowed inside transactions except as the first request
after box.begin()
.
Ниже приведен перечень всех функций для управления транзакциями.
Имя | Использование |
---|---|
box.begin() | Начало транзакции |
box.commit() | Окончание транзакции и сохранение всех изменений |
box.rollback() | Окончание транзакции и отмена всех изменений |
box.savepoint() | Получение дескриптора точки сохранения |
box.rollback_to_savepoint() | Запрещение окончания транзакции и отмена всех изменений, сделанных после точки сохранения |
box.atomic() | Выполнение функции как транзакции |
box.on_commit() | Определение триггера, активируемого по box.commit |
box.on_rollback() | Определение триггера, активируемого по box.rollback |
box.is_in_txn() | Обозначение наличия активной транзакции |
-
box.
begin
() Начало транзакции. Отключение неявной передачи управления до окончания транзакции. Сигнал о записи в журнал упреждающей записи будет задержан до окончания транзакции. Фактически файбер, который выполняет функцию
box.begin()
, начинает «активную транзакцию со множеством запросов» с блокировкой всех остальных файберов.- Возможные ошибки: ошибка, если такая операция не допускается, потому что
- уже есть активная транзакция. ошибка, если по какой-либо причине нельзя выделить память.
-
box.
commit
() Окончание транзакции и применение результатов всех операций по изменению данных.
- Возможные ошибки: ошибка и прерывание транзакции в случае конфликта.
- ошибка, если операция не может выполнить запись на диск. ошибка, если по какой-либо причине нельзя выделить память.
-
box.
rollback
() Окончание транзакции, но отмена результатов всех операций по изменению данных. Явный вызов функций не из модуля
box.space
, которые всегда передают управление, например fiber.sleep() или fiber.yield(), приведет к тому же результату.
-
box.
savepoint
() Возврат дескриптора точки сохранения (тип = таблица), который может затем использоваться в box.rollback_to_savepoint(savepoint). Точки сохранения могут быть созданы, пока активна транзакция, и удаляются после окончания транзакции.
возвращается: таблица точки сохранения тип возвращаемого значения: Lua-объект возвращается: ошибка, если точку сохранения нельзя указать в отсутствие активной транзакции. Возможные ошибки: ошибка, если по какой-либо причине нельзя выделить память.
-
box.
rollback_to_savepoint
(savepoint) Запрещение окончания транзакции, но отмена всех изменений и операций box.savepoint(), сделанных после точки сохранения.
возвращается: ошибка, если точку сохранения нельзя указать в отсутствие активной транзакции. Возможные ошибки: ошибка, если отсутствует точка сохранения.
Пример:
function f() box.begin() -- начало транзакции box.space.t:insert{1} -- это не отменится local s = box.savepoint() box.space.t:insert{2} -- это отменится box.rollback_to_savepoint(s) box.commit() -- конец транзакции end
-
box.
atomic
(tx-function[, function-arguments]) Выполнение функции так, как будто функция начинается с явного вызова box.begin() и заканчивается неявным вызовом box.commit() после успешного выполнения или же заканчивается неявным вызовом box.rollback() в случае ошибки.
возвращается: результат функции передается в atomic()
в качестве аргумента.- Возможные ошибки: любая ошибка, которую могут вызвать box.begin()
- и box.commit().
-
box.
on_commit
(trigger-function[, old-trigger-function]) Определения триггера, выполняемого в случае окончания транзакции в связи с box.commit.
Функция с триггером может принимать параметр с итератором, как описано в примере к данному разделу.
Функция с триггером не должна получать доступ к любым спейсам базы данных.
Если триггер не сработает и выдаст ошибку, результат будет неблагоприятным, чего следует избегать – используйте Lua-механизм
pcall()
вокруг кода, который может не сработать.box.on_commit()
следует вызывать в пределах транзакции, и триггер прекращает существование по окончании транзакции.Параметры: - trigger-function (function) – функция, в которой будет триггер
- old-trigger-function (function) – существующая функция с триггером, которую заменит новая
возвращается: nil или указатель функции
Если указаны параметры
(nil, old-trigger-function)
, старый триггер будет удален.Подробная информация о характеристиках триггера находится в разделе Триггеры.
Простой и бесполезный пример: покажет, что произошел коммит:
function f() function f() print('commit happened') end box.begin() box.on_commit(f) box.commit()
Но, конечно, это еще не всё: параметр функции может быть ИТЕРАТОРОМ.
Итератор проходит по результатам каждого запроса изменения спейса в пределах транзакции.
Итератор будет содержать:
- порядковый номер запроса,
- старое значение кортежа до запроса (для запросов вставки это будет нулевое значение nil),
- новое значение кортежа после запроса (для запросов удаления это будет нулевое значение nil),
- и идентификатор спейса.
Более сложный и более полезный пример: покажет результат двух запросов замены:
box.space.test:drop() s = box.schema.space.create('test') i = box.space.test:create_index('i') function f(iterator) for request_number, old_tuple, new_tuple, space_id in iterator() do print('request_number ' .. tostring(request_number)) print(' old_tuple ' .. tostring(old_tuple[1]) .. ' ' .. old_tuple[2]) print(' new_tuple ' .. tostring(new_tuple[1]) .. ' ' .. new_tuple[2]) print(' space_id ' .. tostring(space_id)) end end s:insert{1,'-'} box.begin() s:replace{1,'x'} s:replace{1,'y'} box.on_commit(f) box.commit()
Результат будет выглядеть следующим образом:
tarantool> box.begin() s:replace{1,'x'} s:replace{1,'y'} box.on_commit(f) box.commit() request_number 1 old_tuple 1 - new_tuple 1 x space_id 517 request_number 2 old_tuple 1 x new_tuple 1 y space_id 517
-
box.
on_rollback
(trigger-function[, old-trigger-function]) Определение триггера, выполняемого по окончании транзакции в связи с box.rollback.
Используются точно такие же параметры и предупреждения, как в box.on-commit.
-
box.
is_in_txn
() В процессе транзакции (например, пользователь вызвал box.begin и еще не вызвал ни box.commit, ни box.rollback) возвращается
true
. В остальных случаях возвращаетсяfalse
.