JayData.org

Database transaction handling in JayData

Author: Gábor Dolla February 28th, 2013

, , , , ,


This feature is only available in the Pro version of WebSQL and IndexedDb provider.

You can download your Pro provider from jaystack.com after a simple registration. For commercial usage you can either evaluate it for 30 days for free or you can buy it. For non-commercial usage it’s free.

(The API is preliminary and might change in the future)

Business apps handle important data. Data that you do not want to lose or get corrupted. Javascript business apps are no different in this aspect. As the capacity of the devices is skyrocketing, a mobile app with a local database can handle millions of records, records of your business data.

A fundamental piece of creating server side code is transaction handling, with transaction handling you can achieve Atomicity, Consistency, Isolation and Durability (ACID). ACID transaction handling is available in local browser databases too (WebSQL and indexedDB) and from version 1.2.7 you can use it from JayData.

We believe that transaction support in JayData is a killer function and our business users will appreciate it. We are not aware of any other library which supports transaction handling in the browser. We take business apps seriously and we continuously improve JayData with new functions that are needed for JayData to became the number one choice for javascript business app development.

We’ll announce even more new killer features really soon! Follow us on Facebook or Twitter to be notified about the new developments!

One more thing to mention: the evolution of JayData is driven by our ideas and experiences but more importantly by the needs of our users. This new feature is developed because one of our users needed it. You can suggest new features and if we find the idea worth developing we add it to our roadmap. Users with support plan can even require concrete development.

JayData uses the transaction capability of the local database (WebSQL, indexedDb) but wraps it so you get a uniform interface independent of the database type. Your code does not have to deal with the device capability, just use ‘local’ and the rest will be handled by JayData. If you try to use it with other providers you’ll get an error.

First of all you might ask: why transaction handling in javascript ?

There are no threads so concurrency won’t cause you a headache. Concurrency can happen in javascript. Every operation is asynchronous so the following code can create problems:

Attach this function to an onclick event of a button and press the button several times. It might or might not work as you expected. first() is an async function so when the javascript engine executes it, the next onclick handler will kick in and so on. first() might be executed several times parallel and all of them will read the same result from the database, so no wonder that all of the parallel event handler functions will insert the same value to the database. This race condition results in different outcomes, sometimes the result is what you expected, sometimes it is not. When you see something like that then suspect race condition. This race condition can only be handled in one way (beside disabling the button): ensuring that the function can not run parallel, no read takes place until the previous read+write has finished. As there are no locks or semaphores in javascript, the best thing that we can do is using the locking capability of the built-in database. Acquiring a write lock on the database ensures that there can not be parallel runs, because only one write lock can exists at a time.

Concurrency can became even more of a problem with the advent of WebWorkers.

But concurrency is not the only problem which can be solved using transactions: atomicity can be equally important. So you can have several saveChanges() in a chain and roll back the whole transaction should you need to.

Transaction handling is only available in the pro version of indexedDb and WebSQL provider. The providers must be manually included, autoloading does not work. The inclusion must be before any local database context created.

Explicit transaction handling  starts with context.beginTransaction(params). You can use it with a callback function as well as with promise:

or

The params are:

array of sets to be locked – optional, default: all tables (websql) or all objectstores (indexeddb)

lock type: optional boolean, default false: read-only, true –> read-write

callback function: optional, called when the transaction has begun, input param is the transaction object

Read-Write lock is exclusive, no other lock can exists parallel. Read-Only lock is co-operative, so other read-only lock(s) can exist for the same resource. When a beginTransaction can not start, because other lock is in place, it will block the execution until a lock can be obtained.

To keep the transaction alive, you have to pass the transaction object as the last parameter in every call which fires a database operation. Failing to do that will close the transaction! Most of the methods accept a callback function as an optional parameter, if you do not want to use it but want to pass the transaction object you have to supply undefined in place of the optional callback function (we might remove this limitation later).

When you supply the transaction object, you also get it back as the last parameter in the result callback.

The first async function call which does not use the transaction object closes the transaction (ajax call, calling an oData database, using JayData without transaction, etc).

The first failure rollbacks the whole transaction automatically. The transaction can be aborted in the success callback (tx.abort()), which will rollback the whole transaction. You can not execute anything after abort().

The transaction object has onerror and oncomplete events to which you can attach your own functions.

Now with this knowledge the example at the beginning of this blogpost can be fixed:

 


, , , , ,