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()); });
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.
Backendless transactions rely on the following concepts:
The diagram below illustrates these concepts as they relate to each other:
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.
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.
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!
Are the transaction also available in Codeless?
Not yet, but we’re adding them very soon.