Версия:

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

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

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

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

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

Правило #1

Запросы в транзакции должны отправляться на сервер в виде единого блока. Недостаточно просто размещать их между началом транзакции и коммитом или откатом. Чтобы убедиться, что они отправляются в виде единого блока: поместите их в функцию, поместите их на одну строку или используйте символы-разделители, чтобы многостроковые запросы обрабатывались совместно.

Правило #2

Все операции с базой данных в рамках транзакции должны работать с одним движком баз данных. Небезопасно в рамках одной транзакции получать доступ к наборам кортежей, которые определяются по {engine='vinyl'}, а также к наборам кортежей, которые определяются по {engine='memtx'}.

Правило #3

Нельзя использовать запросы, которые могут приводить к изменению определения данных – создание, изменение, удаление, очистка.

Индекс

Ниже приведен перечень всех функций для управления транзакциями.

Имя Использование
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(), начинает «активную транзакцию со множеством запросов» с блокировкой всех остальных файберов.

Возможные ошибки: ошибка, если такая операция не допускается, потому что
уже есть активная транзакция. ошибка, если по какой-либо причине нельзя выделить память.
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.