Версия:

Управление экземплярами

Управление экземплярами

Общие сведения

Чтобы получить общую информацию и взглянуть на примеры использования, см. раздел Управление транзакциями.

Соблюдайте следующие правила в работе с транзакциями:

Правило #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()

Начало транзакции. Отключение неявной передачи управления до окончания транзакции. Сигнал о записи в :ref :журнал упреждающей записи <internals-wal> будет задержан до окончания транзакции. Фактически файбер, который выполняет функцию box.begin(), начинает «активную транзакцию со множеством запросов» с блокировкой всех остальных файберов.

Possible errors: error if this operation is not permitted because there
is already an active transaction. error if for some reason memory cannot be allocated.
box.commit()

Окончание транзакции и применение результатов всех операций по изменению данных.

Possible errors: error and abort the transaction in case of a conflict.
error if the operation fails to write to disk. error if for some reason memory cannot be allocated.
box.rollback()

Окончание транзакции, но отмена результатов всех операций по изменению данных. Явный вызов функций не из модуля box.space, которые всегда передают управление, например fiber.sleep() или fiber.yield(), приведет к тому же результату.

box.savepoint()

Возврат дескриптора точки сохранения (тип = таблица), который может затем использоваться в box.rollback_to_savepoint(savepoint). Точки сохранения могут быть созданы, пока активна транзакция, и удаляются после окончания транзакции.

возвращается:таблица точки сохранения
тип возвращаемого значения:
 Lua-объект.
возвращается:ошибка, если точку сохранения нельзя указать в отсутствие активной транзакции.

Possible errors: error if for some reason memory cannot be allocated.

box.rollback_to_savepoint(savepoint)

Запрещение окончания транзакции, но отмена всех изменений и операций box.savepoint(), сделанных после точки сохранения.

возвращается:ошибка, если точку сохранения нельзя указать в отсутствие активной транзакции.

Possible errors: error if the savepoint does not exist.

Пример:

function f()
  box.begin()           -- start transaction
  box.space.t:insert{1} -- this will not be rolled back
  local s = box.savepoint()
  box.space.t:insert{2} -- this will be rolled back
  box.rollback_to_savepoint(s)
  box.commit()          -- end transaction
end
box.atomic(tx-function[, function-arguments])

Выполнение функции так, как будто функция начинается с явного вызова box.begin() и заканчивается неявным вызовом box.commit() после успешного выполнения или же заканчивается неявным вызовом box.rollback() в случае ошибки.

возвращается:результат функции передается в atomic() в качестве аргумента.
Possible errors: any error that box.begin() and
box.commit() can return.
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.