Blog

Introducing The Transactions API

by on June 17, 2020

Introducing the Transactions API Feature

With the Transactions API, Backendless Database can execute multiple database requests grouped into a single transaction. When any one of these grouped database operations fails, the entire transaction is rolled back – meaning any other changes within the same transaction are canceled.

With the release of Version 6, client applications and Backendless Cloud Code (business logic) can use this functionality via Transaction API.

A single transaction can include multiple create, update, delete, retrieve and relation management (set/add/delete) operations. The result of an operation can then be used as an input parameter in any of the subsequent ones.

Consider the example below. The example stores an object in a table and then creates a relation between that object and some others identified with a query from another table:

// create a UnitOfWork instance - it represents a transaction and
// will accumulate all operations in it.
const uow = new Backendless.UnitOfWork();

// Create a person object
const person = {
    name:"Joe",
    age:20
}

// add a "create" operation to the transaction
// notice the result object will be reused later on
const createPersonOpResult = uow.create( "Person", person );

// add an operation to create a relation. This operation uses
// the result from the previous "create" operation
uow.setRelation( createPersonOpResult, "visitedCountries", "name = 'China'" );

// execute the transaction.
uow.execute()
.then( function(unitOfWorkResult) {
        console.log("Transaction is successful " + unitOfWorkResult.isSuccess());
   });

Benefits Of Transactions

There are several benefits of using transactions:

If any of the operations fail, the entire transaction is rolled back – there is no need to perform any clean up from your code.

From the client-side perspective, there is only one request going to the server – the request to execute the transaction. For instance, the example above performs two operations: (1) saving an object in the database and (2) establishing a relationship between the saved object and others identified with a query. However, the client application sends only one request to the server.

Consistency and referential integrity – transactions ensure that there is no “dirty data” in your database. This helps with keeping your client-side code cleaner and the data consistent.

How the Transactions API Works

Backendless transactions rely on the following concepts:

  • Unit of Work – is the entire payload of the transaction request which combines multiple individual database operations into a single object. All operations added to a unit of work have a sequence number and will be executed on the server-side in the same order they were added. A unit of work essentially represents a transaction; for more information, see the Unit of Work section of the documentation.
  • Database Operation – a single operation executed within a transaction. This can be either a create, retrieve, update, delete and relation management (create, update, delete) operation;
  • Operation Result – an entity representing the result of an individual database operation. The result of one operation can be referenced in other subsequent operations. You can see an example of it in the sample request shown above. For example, a “create” operation returns a result. The result represents the object saved in the database. That object may be referenced in an operation to set a relationship for the object. Alternatively, you can “extract” the value of a specific property from the operation result and also use it in other operations in the same transaction.

The diagram below illustrates these concepts as they relate to each other:

Unit of Work Diagram

Unit of Work API

The heart of the Backendless Transactions API is a request called UnitOfWork. It is used by client applications to compose a transaction.

Composing a transaction means adding various database operations to a unit of work. These operations may be “linked” to each other by using the output/result on one operation as the input for another.

When the server receives a UnitOfWork request, it starts processing its operations. The server executes all operations one-by-one in the context of a single database transaction.

If any of the operations fails, Backendless rolls back all the changes and returns the information about the result of each operation to the client. However, if all operations succeed, the entire database transaction is committed. This means the data will be finalized in the database.

Transaction Isolation

Using Backendless transactions API you can configure an isolation level for your transaction. The isolation level determines how the Backendless database separates your transaction from all others running at the same time.

Without any isolation, one transaction could modify the data another transaction is reading and, by doing so, data inconsistency would be created.

Isolation levels determine how isolated your transaction is from others. This is implemented by applying a lock on the data retrieved in a transaction.

Different levels of isolation imply different locking mechanisms, which also yield various data read phenomena (described further in the documentation). Backendless supports four isolation levels.

Operation Result

One of the most powerful elements of the Backendless Transactions API is the ability to use the result of an operation in other subsequent operation(s) within the same transaction. This is made possible by a “protocol” that all transactional operations follow: every operation can have a unique identifier.

The identifier can be used in another operation to reference the result from the operation where it was used. This allows for a “chaining effect” where data comes out of one operation and is then fed into another.

Consider the example below. The example saves a new object in the database and then establishes a relationship between the created object and objects in another table.

As you can see, the operation to save the object in the database assigns a unique id to the operation with the opResultId property, which then is used in the subsequent operation to establish a relationship between the object and its children:

// create a UnitOfWork instance - it represents a transaction and
// will accumulate all operations in it.
const uow = new Backendless.UnitOfWork();

// Create a person object
const person = {
    name:"Joe",
    age:20
}

// add a "create" operation to the transaction
// notice the result object will be reused later on
const createPersonOpResult = uow.create( "Person", person );

// add an operation to create a relation. This operation uses
// the result from the previous "create" operation
uow.setRelation( createPersonOpResult, "visitedCountries", "name = 'China'" );

// execute the transaction.
const result = uow.execute()
.then( function( unitOfWorkResult ) {
        console.log("Transaction is successful " + unitOfWorkResult.isSuccess());
});

The most important in the example above is how the result from the "CREATE" operation is used in the "SET_RELATION" operation. Read more about this aspect of the Transaction API in the Operation Result documentation.


The Transaction API is an extremely powerful tool for protecting your data from failed operations. It allows you to ensure that partial data changes do not dirty your database.

We look forward to seeing what you do with this awesome new functionality!

Check out everything else released in Version 6 so far.

Happy Coding!

2 Comments

Are the transaction also available in Codeless?

Not yet, but we’re adding them very soon.

Leave a Reply