logo XWiki Platform - Core - Storage - Transaction

The common and error prone way of saving things in the database is to open a transaction, enter a try clause, do something then commit. If we catch an exception, then we rollback. something like this: begin transaction; try { do something; do something else; commit; } catch (Any exception which may occur) { rollback; } There are 3 things which can go wrong. 1 we forget to begin the transaction, 2 we forget to commit and 3 we do not rollback properly. What makes things worse is often the database will "assume we meant to..." and things will work okay most of the time which makes things much worse because bugs will hide very well. This module answers the problem with a class called TransactionRunnable. It provides a set of 5 empty methods to override: onPreRun(), onRun(), onCommit(), onRollback(), and onComplete(). the exact circumstances under which each are called is documented in the javadoc comments. To repeat our original example with TransactionRunnable you might say this: public class DoSomethingTransactionRunnable extends TransactionRunnable { public void onRun() { do something; do something else; } } Now we can use another TransactionRunnable which opens and closes the transaction for us. StartableTransactionRunnable transaction = new SQLTransactionRunnable(); new DoSomethingTransactionRunnable().runIn(transaction); transaction.start(); the runIn() function allows us to run one TransactionRunnable inside of another. Supposing we wanted to reuse "do something else" in other places, we can make it a separate TransactionRunnable and use the runIn() function to hook it to our DoSomethingTransactionRunnable IE: public class DoSomethingTransactionRunnable extends TransactionRunnable { public DoSomethingTransactionRunnable() { new DoSomethingElseTransactionRunnable().runIn(this); } .. The only limitations on running TransactionRunnables inside of one another are they cannot run more than once and they cannot call themselves (this would be an infinite loop). This pattern makes each job which is done on storage easily isolated and, as I have so far experienced, trivial to test. However, it still leaves the possibility that we might forget that DoSomethingTransactionRunnable must be run inside of a database transaction. This module provides a solution for this too. Using generics, it offers a means for the author of a TransactionRunnable to communicate to the compiler what other TransactionRunnable their runnable must be run in and without explicit casting or defining of an intermediary runnable, this requirement cannot be violated or else it wouldn't compile! Finally we have the issue of starting the runnable. Who's to say I won't be tired one day and just write "new DoSomethingTransactionRunnable().start()" without opening a transaction first? If DoSomethingTransactionRunnable cannot be safely run outside of a transaction all it needs to do is not extend StartableTransactionRunnable and it won't have any start function. This module takes a multitude of very easy mistakes and gives the author of a TransactionRunnable the tools to make it very hard for the user to make them. Also, since a TransactionRunnable has no reason to be very long (it can just branch off into another runnable) this will make testing and code review easy in the place where it is most important. This part of the code is entirely generic and has no dependence on any type of underlying transactional storage engine.

homepage:
fresh index:
last release: 5 years ago, first release: 6 years ago
packaging: jar
get this artifact from: xwiki





This chart shows how much is this artifact used as a dependency in other Maven artifacts in Central repository and GitHub:



© Jiri Pinkas 2015 - 2016. Admin login To submit bugs / feature requests please use this github page
related: JavaVids | Top Java Blogs | Java školení | monitored using: sitemonitoring
Apache and Apache Maven are trademarks of the Apache Software Foundation. The Central Repository is a service mark of Sonatype, Inc.