Reference / Built-in modules reference / Module box / Functions for transaction management
Reference / Built-in modules reference / Module box / Functions for transaction management

Functions for transaction management

Functions for transaction management

Overview

For general information and examples, see section Transaction control.

Observe the following rules when working with transactions:

Rule #1

The requests in a transaction must be sent to a server as a single block. It is not enough to enclose them between begin and commit or rollback. To ensure they are sent as a single block: put them in a function, or put them all on one line, or use a delimiter so that multi-line requests are handled together.

Rule #2

All database operations in a transaction should use the same storage engine. It is not safe to access tuple sets that are defined with {engine='vinyl'} and also access tuple sets that are defined with {engine='memtx'}, in the same transaction.

Rule #3

Requests which cause changes to the data definition – create, alter, drop, truncate – must not be used.

Index

Below is a list of all functions for transaction management.

Name Use
box.begin() Begin the transaction
box.commit() End the transaction and save all changes
box.rollback() End the transaction and discard all changes
box.savepoint() Get a savepoint descriptor
box.rollback_to_savepoint() Do not end the transaction and discard all changes made after a savepoint
box.atomic() Execute a function, treating it as a transaction
box.on_commit() Define a trigger that will be activated by box.commit
box.on_rollback() Define a trigger that will be activated by box.rollback
is_in_txn() State whether a transaction is in progress
box.begin()

Begin the transaction. Disable implicit yields until the transaction ends. Signal that writes to the write-ahead log will be deferred until the transaction ends. In effect the fiber which executes box.begin() is starting an “active multi-request transaction”, blocking all other fibers.

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

End the transaction, and make all its data-change operations permanent.

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

End the transaction, but cancel all its data-change operations. An explicit call to functions outside box.space that always yield, such as fiber.sleep() or fiber.yield(), will have the same effect.

box.savepoint()

Return a descriptor of a savepoint (type = table), which can be used later by box.rollback_to_savepoint(savepoint). Savepoints can only be created while a transaction is active, and they are destroyed when a transaction ends.

Return:savepoint table
Rtype:Lua object
Return:error if the savepoint cannot be set in absence of active transaction.
Return:error if for some reason memory cannot be allocated.
box.rollback_to_savepoint(savepoint)

Do not end the transaction, but cancel all its data-change and box.savepoint() operations that were done after the specified savepoint.

Return:error if the savepoint cannot be set in absence of active transaction.
Return:error if the savepoint does not exist.

Example:

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(function-name[, function-arguments])

Execute a function, acting as if the function starts with an implicit box.begin() and ends with an implicit box.commit() if successful, or ends with an implicit box.rollback() if there is an error.

Return:the result of the function passed to atomic() as an argument.
Return:any error that box.begin() and box.commit() can return.
box.on_commit(trigger-function[, old-trigger-function])

Define a trigger for execution when a transaction ends due to an event such as box.commit.

The trigger function may take an iterator parameter, as described in an example for this section.

The trigger function should not access any database spaces.

If the trigger execution fails and raises an error, the effect is severe and should be avoided – use Lua’s pcall() mechanism around code that might fail.

box.on_commit() must be invoked within a transaction, and the trigger ceases to exist when the transaction ends.

Parameters:
  • trigger-function (function) – function which will become the trigger function
  • old-trigger-function (function) – existing trigger function which will be replaced by trigger-function
Return:

nil or function pointer

If the parameters are (nil, old-trigger-function), then the old trigger is deleted.

Details about trigger characteristics are in the triggers section.

Simple and useless example: this will display ‘commit happened’:

function f()
function f() print('commit happened') end
box.begin() box.on_commit(f) box.commit()

But of course there is more to it: the function parameter can be an ITERATOR.

The iterator goes through the effects of every request that changed a space during the transaction.

The iterator will have:

  • an ordinal request number,
  • the old value of the tuple before the request (this will be nil for an insert request),
  • the new value of the tuple after the request (this will be nil for a delete request),
  • and the id of the space.

Less simple more useful example: this will display the effects of two replace requests:

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()

The result will look like this:

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])

Define a trigger for execution when a transaction ends due to an event such as box.rollback.

The parameters and warnings are exactly the same as for box.on-commit.

box.is_in_txn()

If a transaction is in progress (for example the user has called box.begin and has not yet called either box.commit or box.rollback, return true. Otherwise return false.