Transactions are a critical part of almost all Enterprise applications, but correctly managing those transactions isn't always easy. This is particularly true in a dynamic, modular world where you need to be certain that everything is ready before you begin.
With the advent of lambda expressions and functional interfaces we now have new, better tools for defining transactional work. The OSGi Transaction Control service uses these functional programming techniques to scope transactions and resource access, providing control and flexibility while leaving business logic uncluttered. The resulting solution is decoupled, modular and requires no container magic at all, making testing and portability a breeze.
Software controlled transactions have existed for a long time — commercial products that are still available now can trace their origins back to the 1960s. Since that time a lot has changed, first we saw the rise of C, then of Object Oriented programming, then of the Web, and now of Microservices.
Over the same time period there have been significant changes to the way that transactions are managed – either transaction boundaries have to be explicitly declared, or the management role is delegated to a container technology. Given the complexity of correctly managing the transaction lifecycle, container managed solutions are regarded as the gold standard, however container managed solutions introduce their own problems.
The rise of the Spring framework was a reaction to the complexity, and heavy-touch management of the original Java EE specifications. Instead Spring focussed on “pure POJO” programming, designed to make your code easily portable, runnable and testable inside or outside the container.
While Spring did a much better job of hiding complexity than those early Java EE servers, the fundamental problem with any pure declarative approach is that there must be a container somewhere. Without a container there is no code to start or end the transaction. Even now with Spring, EJB 3.2, CDI etc, the promise of simpler, container independent components is an illusion.
The big problem with declarative transaction management is that it tries to take away too much from the application code, replacing it with “container magic”. The problem with relying on magic is that the resulting system ends up being more complex, not less. We therefore should be aiming to simplify and minimise transaction management code, not eliminate it entirely. Java’s support for functional techniques opens a whole new set of API possibilities for transaction management, and the Apache Aries project has been exploring the possibilities of providing generic resource and transaction management in a concise, type-safe way. Examples from this project demonstrate how transaction management can be made both simple and explicit at the same time.