Wednesday, November 22, 2017

Easily Return Values From a Transaction with Speedment 3.0.17 or Later

Transactions

In my previous post, I wrote about how to use Transactions in an easy way using Speedment where we updated two bank accounts atomically. As you all might know, transactions are a way of combining a number of database operation into a single operation that is atomically executed.

But transactions are not only about updating the database but also about performing atomic reads. With Speedment, we can compute values atomically using Java streams and then return the result to something outside the scope of the transaction in an easy way.

Returning Transaction Values

Suppose we have a database with films and artists (e.g. using the open-sourced Sakila database content for MySQL) and we would like to count the number of films plus the number of artist in the database in a single transaction. This might be the case if we want to show some kind of database size in a GUI or the likes. Here is how it might look like:

    long sumCount = txHandler.createAndApply(tx -> 
        films.stream().count() + actors.stream().count()
    );

When the transaction starts, the view of the database is "frozen" so that new films or artist that are inserted into the database by other threads are not visible within the transaction. Thus, we can safely assume that our view is unaffected by other threads.

As can be seen, with really minimal boiler plate code, we can express functions that are to be performed within transactions using Speedment.

Preparations

Before transactions can be used, we need to obtain a TransactionHandler like this:

    SakilaApplication app = ....
    TransactionComponent transactionComponent = app.getOrThrow(TransactionComponent.class);
    TransactionHandler txHandler = transactionComponent.createTransactionHandler();

The FilmManager and the ActorManager can be retrieved from the application as shown hereunder:

    FilmManager films = app.getOrThrow(FilmManager.class);
    ActorManager actors = app.getOrThrow(ActorManager.class);

Read more on Speedment transactions here.

What's Next?


Visit Speedment open-source on GitHub and try it out!

Tuesday, November 14, 2017

Transactions Made Simple Using Speedment 3.0.17 and Above

Transactions

Sometimes we want to make sure that our database operations are executed atomically and separated from other operations. This is where transactions come into play. A transaction is a set of operation
proposals that may or may not be accepted by the database as an atomic operation. So, either all operations in the transaction are accepted or no operations of the transaction are accepted. Another advantage with transaction is that the state of the database will be locally "frozen" when the transaction starts, so we will not see updates by other threads while in the transaction.

Speedment is an open-source Stream ORM Java Toolkit and Runtime Java tool that wraps an existing database and its tables into Java 8 streams. Later versions of Speedment support database transactions in an easy-to-use way.

Updates

Imagine we are writing a bank application with accounts and we are going to move $100 from one account (1) to another (2). In this case it is important that money does not disappear (i.e. is deducted from 1 but never deposited in 2) or perhaps even worse, will be duplicated (i.e. deposited in 2 but not deducted from 1). This can be assured using a Speedment database transaction like this:
txHandler.createAndAccept(tx ->

    Account sender = accounts.stream()
        .filter(Account.ID.equal(1))
        .findAny()
        .get();

    Account receiver = accounts.stream()
        .filter(Account.ID.equal(2))
        .findAny()
        .get();

    accounts.update(sender.setBalance(sender.getBalance() - 100));
    accounts.update(receiver.setBalance(receiver.getBalance() + 100));

    tx.commit();
}
When the method tx.commit() is called, the two updates are committed to the database atomically and will be visible to all other threads. If we do not call tx.commit() explicitly then the transaction will be automatically rolled back (i.e. the updates will not have any effect and will be discarded).

Preparations

Before transactions can be used, we need to obtain a TransactionHandler like this:
    BankApplication app = ....
    TransactionComponent transactionComponent = app.getOrThrow(TransactionComponent.class);
    TransactionHandler txHandler = transactionComponent.createTransactionHandler();
The AccountManager can be retrieved from the application as shown hereunder:
    AccountManager accounts = app.getOrThrow(AccountManager.class);

What's Next?

Read more on Speedment transactions here.

Visit GitHub and read all about Speedment open-source here.