How to Transaction Management » History » Revision 14
« Previous |
Revision 14/29
(diff)
| Next »
Henning Blohm, 17.09.2012 15:15
Transaction management in Z2¶
(work in progress)
This page provides some hints and pointers on how to implement transaction management for modular applications on Z2. There are a few utilities provided with Z2 that may help you implement transaction handling for the simple cases, and this site provides examples that show how to address the more complicated cases.
Everything below is describing use and enabling of a Java Transaction API (JTA) based approach to transaction management.
Note that there is nothing in Z2 that prevents you from using a previously implemented Web application-local based transaction management. The information on this page is most useful, if you have a modular application that requires transaction management also on a service level.
The following aspects will be discussed:
- The built-in, non-XA JTA implementation of Z2
- Controlling transactions in code
- Using Datasource components
- Using Hibernate JPA
- Using a full-blown transaction manager
- Integration with Jetty
- Integration with Spring
The built-in, non-XA JTA implementation of Z2 (com.zfabrik.jta)¶
The z2-base.base repository contains the JTA 1.1 API and an implementation of it in the module com.zfabrik.jta.
Note: This is not an XA-capable transaction manager. This implementation provides no atomic transaction control for more than one transactional resource!
But, this implementation is still most useful, if you do not need distributed transactions (which is preferable in most cases) and still want to benefit from the JTA API as an integration point.
Technically the implementation relies on Z2's Unit of Work abstraction (see Unit of Work and transaction management). As long as all interactions with an application are issued from a Web application this is completely transparent. When invoking code from other entry points, e.g. from an embedded scheduling service for example, this has an impact that will be discussed below.
The TransactionManager interface, as well as the UserTransaction interface are available from the component com.zfabrik.jta/userTransaction and can be looked up via the Z2 core API
IComponentsLookup.INSTANCE.lookup("com.zfabrik.jta/userTransaction",TransactionManager.class)
or via JNDI as
new InitialContext().lookup("components:com.zfabrik.jta/userTransaction?type=javax.transaction.TransactionManager")
and similarly for the UserTransaction interface.
This simple approach to JTA has been used in the samples Sample-hibernate-basic-TBD and Sample-spring-hibernate-TBD.
Controlling transactions in code¶
Now that you have a JTA implementation you need to indicate where transactions start and end. The most basic (and most understandable) approach to that is to use the UserTransaction interface. Typically in a flow like this:
UserTransaction ut = (UserTransaction) new InitialContext().lookup( JNDI_NAME );
ut.begin();
try {
// do some work
} catch (Exception e) {
logger.log(Level.WARNING,"Error at transaction boundary. Setting transaction to rollbackonly",e);
ut.setRollbackOnly();
throw e;
} finally {
if (ut.getStatus()==Status.STATUS_ACTIVE) {
ut.commit();
} else {
ut.rollback();
}
}
The constant JNDI_NAME is intentionally left undefined here. If you use com.zfabrik.jta you may use the name specified above. If the code above is part of a Servlet Filter that is supposed to begin and end transactions on the boundaries of a Web request, you can use the standard name "java:comp/UserTransaction" given you integrated the transaction management with Jetty (see below).
Now that we looked at it, fortunately you do not need to implement this yourself. Here are some alternatives:
- Use TransactionUtil from com.zfabrik.jta that implements just the flow above.
- Use Spring's transaction management support including annotation based transaction demarcation, as for example in Sample-spring-hibernate-TBD and Sample-jta-spring (see also How to Spring).
- Use any of the many "Transaction Filter" implementations out there.
Using DataSource components¶
A JDBC data source wraps JDBC connections, i.e. actual database connections, for re-use along the control flow.
When accessing the same database multiple times within one transaction, you want to make sure you re-use the same (underlying) JDBC connection. That is, you may (typically) not have more than one (underlying) JDBC connection to the very same database that share the same (non-distributed) transaction. Hence the typical implementation associates a JDBC connection to a database with the transaction that is associated with the current thread of execution. Obviously there is a strong tie between the management of database connections and the transaction management system. JDBC data sources provide the accessor interface to database connections. You may hold of to a data source and ask it for a connection when needed, but you should not hold on to the actual connection object between invocations of your service interface.
Z2 offers a built-in DataSource component type. This is useful, if you use com.zfabrik.jta. If you use another transaction management system, you should most likely use another data source implementation. See for example Sample-jta-plain.
When using the built-in data source, you can look up the DataSource interface via a component lookup, e.g. via JNDI like this:
(DataSource) new InitialContext().lookup(COMPONENT_NAME?type=javax.sql.DataSource)
where COMPONENT_NAME has to be substituted by the real name of the data source component.
The built-in data sources have been used for example in Sample-hibernate-basic-TBD and Sample-spring-hibernate-TBD.
Using Hibernate and JPA¶
Now you have a JTA implementation in place as well as data sources defined, assuming you want to use the Java Persistence API you buy into yet another layer that needs to be integrated with the transaction management system.
In JPA, the equivalent of a data base connection is the EntityManager interface. And as with connections and data sources, you will want to reuse the entity manager instance across invocations within one transaction. An entity manager is created from an EntityManagerFactory given a definition of a Persistence Unit. We cannot go into all the details here.
In Java EE environments, you may delegate the creation of entity managers to the container and have it injected into your code using a corresponding annotation. The same comfort (and beyond that) can be achieved in Z2 even across modules using the Spring framework (see for example Sample-spring-hibernate-TBD and Sample-jta-spring).
The underlying implementation however is always about associating an entity manager with the ongoing transaction. If you do not want to use Spring or want to fully understand the principle mechanics, you may use the EntityManagerUtil of the module org.hibernate in *z2-base.base". This is how it is done in Sample-hibernate-basic.
To connect a persistence unit (and hence the entity manager factory) with the transaction management and the data source to use, you add corresponding information to the file META-INF/persistence.xml of your domain module. For example, the one in Sample-hibernate-basic looks like this:
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
<persistence-unit name="thingies" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>components:com.zfabrik.samples.hibernate-basic.domain/DB</jta-data-source>
<class>com.zfabrik.samples.hibernate_basic.thingies.Thingy</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.jdbc.batch_size" value="10" />
<property name="hibernate.cache.use_second_level_cache" value="false" />
<property name="hibernate.transaction.manager_lookup_class" value="com.zfabrik.hibernate.TransactionManagerLookup" />
</properties>
</persistence-unit>
</persistence>
The noteworthy pieces are
- The <jta-data-source/> definition that uses a DataSource JNDI name as discussed above.
- The <property name="hibernate.transaction.manager_lookup_class"/> declaration
The latter is required for Hibernate to find the transaction manager instance. Unfortunately Hibernate does not support a JNDI name for that. That's why the module org.hibernate provides an implementation you can use (it's really simple. See TransactionManagerLookup).
When not using com.zfabrik.jta, the value to specify differ of course. See also Samples-jta-plain.
Using a full-blown transaction manager¶
The sample Samples-jta-plain and Samples-jta-spring illustrate how to integrate the Atomikos transaction manager in a hand-wired application or in a Spring configured way resp. While it does help to understand the contents of this page, further details are to be found in the explanations of the samples.
Integration with Jetty¶
The Jetty Web Container that comes with Z2 can be configured to integrate with a transaction manager (see e.g. Jetty JNDI). The most notable impact is that you can use the JNDI name "java:comp/UserTransaction" to retrieve the UserTransaction interface from within the Web application. Note: This lookup is valid as long as the current thread's context class loader is the class loader of the Web application. Practically speaking this means it is safe to rely on this name while within the code of the Web application. When switching threads or invoking modules that may for some reason switch the context class loader or when invoked from another entry point to your application this may not be the case.
When using com.zfabrik.jta, having
<New id="tx" class="org.eclipse.jetty.plus.jndi.Transaction">
<Arg>
<New class="com.zfabrik.tx.UserTransaction"/>
</Arg>
</New>
in environment/webServer/jetty.xml does the trick. In other setups this varies. Please check the JTA samples mentioned above for an example of another configuration.
Integration with Spring¶
Integration with Spring is yet another subject on its own. Please see the details on Samples-spring-hibernate-TBD for more on that.
Summary¶
It is not as complex as it sounds. This page intentionally goes into some depths to give an understanding on a subject that often is ignored until failing, which is exactly when it is late to understand and correct assumptions. It will be best to pick one of the samples that best fits to your situation and take it from there.
Updated by Henning Blohm over 12 years ago · 14 revisions