Project

General

Profile

How to Transaction Management » History » Version 29

Henning Blohm, 03.05.2014 20:14

1 10 Henning Blohm
h1. Transaction management in Z2
2 3 Henning Blohm
3 15 Henning Blohm
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 the site provides examples that show how to address the more complicated cases.
4 1 Henning Blohm
5 24 Henning Blohm
In short: You can use mostly any way of transaction management you can use in Java elsewhere.
6 12 Henning Blohm
7 26 Henning Blohm
A hint for Spring users: If your focus is on using Spring's built-in transaction management and data source configuration features, skip to [[How_to_Transaction_Management#Using Spring data sources and the Spring transaction manager|Using Spring data sources and the Spring transaction manager]].
8 12 Henning Blohm
9
The following aspects will be discussed:
10
11 27 Henning Blohm
* [[How_to_Transaction_Management#The built-in, non-XA JTA implementation of Z2 (com.zfabrik.jta)|The built-in, non-XA JTA implementation of Z2 (com.zfabrik.jta)]]
12
* [[How_to_Transaction_Management#Controlling transactions in code|Controlling transactions in code]]
13 28 Henning Blohm
* [[How_to_Transaction_Management#Using Z2 DataSource components|Using Z2 DataSource components]]
14
* [[How_to_Transaction_Management#Using Hibernate and JPA with Z2 data sources|Using Hibernate and JPA with Z2 data sources]]
15
* [[How_to_Transaction_Management#Using a full-blown transaction manager|Using a full-blown transaction manager]]
16
* [[How_to_Transaction_Management#Using Spring data sources and the Spring transaction manager|Using Spring data sources and the Spring transaction manager]]
17
* [[How_to_Transaction_Management#Integration of non-Spring Transaction Managers with Spring|Integration of non-Spring Transaction Managers with Spring]]
18
* [[How_to_Transaction_Management#Integration with Jetty|Integration with Jetty]]
19
* [[How_to_Transaction_Management#Appendix|Appendix]]
20 12 Henning Blohm
21
h2. The built-in, non-XA JTA implementation of Z2 (com.zfabrik.jta)
22
23
The "z2-base.base":http://redmine.z2-environment.net/projects/z2-base/repository/base repository contains the JTA 1.1 API and an implementation of it in the module *com.zfabrik.jta*. 
24
25
*Note*: This is not an XA-capable transaction manager. This implementation provides no atomic transaction control for more than one transactional resource!
26
27
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.
28
29
Technically the implementation relies on Z2's _Unit of Work_ abstraction (see "Unit of Work and transaction management":http://www.z2-environment.eu/v21doc#Unit%20of%20Work%20and%20transaction%20management). 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.
30
31
The "TransactionManager":http://docs.oracle.com/javaee/6/api/javax/transaction/TransactionManager.html interface, as well as the "UserTransaction":http://docs.oracle.com/javaee/6/api/javax/transaction/UserTransaction.html interface are available from the component *com.zfabrik.jta/userTransaction* and can be looked up via the Z2 core API
32
33
<pre><code class="java">IComponentsLookup.INSTANCE.lookup("com.zfabrik.jta/userTransaction",TransactionManager.class)</code></pre>
34
35
or via JNDI as
36
37
<pre><code class="java">new InitialContext().lookup("components:com.zfabrik.jta/userTransaction?type=javax.transaction.TransactionManager")</code></pre>
38
39
and similarly for the UserTransaction interface.
40
41 19 Henning Blohm
This simple approach to JTA has been used in the samples [[Sample-hibernate-basic]] and [[Sample-spring-hibernate]].
42 12 Henning Blohm
43
h2. Controlling transactions in code
44
45
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:
46
47
<pre><code class="java">
48
UserTransaction ut = (UserTransaction) new InitialContext().lookup( JNDI_NAME );
49
ut.begin();
50
try {
51
  // do some work
52
} catch (Exception e) {
53
  logger.log(Level.WARNING,"Error at transaction boundary. Setting transaction to rollbackonly",e);
54
  ut.setRollbackOnly();
55
  throw e;
56
} finally {
57
  if (ut.getStatus()==Status.STATUS_ACTIVE) {
58
    ut.commit();
59
  } else {
60
    ut.rollback();
61
  }
62
}
63
</code></pre>
64
65
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).
66
67 23 Henning Blohm
Now that we looked at it, typically you do not need to implement this yourself. Here are some alternatives:
68 12 Henning Blohm
69 23 Henning Blohm
* Use "TransactionUtil":http://redmine.z2-environment.net/projects/z2-base/repository/base/revisions/master/entry/com.zfabrik.jta/java/src.api/com/zfabrik/tx/TransactionUtil.java from 
70
*com.zfabrik.jta* that implements just the flow above.
71 1 Henning Blohm
* Use any of the many "Transaction Filter" implementations out there.
72 23 Henning Blohm
73 1 Henning Blohm
If you are using Spring:
74 23 Henning Blohm
* Use Spring's transaction management support including annotation based transaction demarcation, as for example in [[Sample-spring-hibernate]] and [[Sample-jta-spring]] (see also [[How to Spring]]). 
75
76
If you use Spring transaction management (over the JTA API), then you should also use Spring mechanisms for transaction demarcation. There is still great value in using JTA beneath, but Spring adds some of its own mechanisms, that are deeply tight in with Spring JPA for example, that will not work correctly using a pure JTA based demarcation.
77
78 12 Henning Blohm
79 24 Henning Blohm
h2. Using Z2 DataSource components
80 12 Henning Blohm
81
A JDBC data source wraps JDBC connections, i.e. actual database connections, for re-use along the control flow. 
82
83
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. 
84
85
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]].
86
87
When using the built-in data source, you can look up the "DataSource":http://docs.oracle.com/javase/6/docs/api/javax/sql/DataSource.html interface via a component lookup, e.g. via JNDI like this:
88
89
<pre><code class="java">(DataSource) new InitialContext().lookup(COMPONENT_NAME?type=javax.sql.DataSource)</code></pre>
90
91 1 Henning Blohm
where *COMPONENT_NAME* has to be substituted by the real name of the data source component.
92
93 19 Henning Blohm
The built-in data sources have been used for example in [[Sample-hibernate-basic]] and [[Sample-spring-hibernate]].
94 12 Henning Blohm
95 15 Henning Blohm
An example definition can be found here: "DB":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-hibernate-basic/revisions/master/entry/com.zfabrik.samples.hibernate-basic.domain/DB.properties.
96
97
The component type *javax.sql.DataSource* is documented here: "DataSources":http://www.z2-environment.eu/v21doc#dataSources.
98 12 Henning Blohm
99 24 Henning Blohm
h2. Using Hibernate and JPA with Z2 data sources
100 12 Henning Blohm
101 13 Henning Blohm
Now you have a JTA implementation in place as well as data sources defined, assuming you want to use the "Java Persistence API":http://de.wikipedia.org/wiki/Java_Persistence_API you buy into yet another layer that needs to be integrated with the transaction management system. 
102
103
In JPA, the equivalent of a data base connection is the "EntityManager":http://docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html 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":http://docs.oracle.com/javaee/6/api/javax/persistence/EntityManagerFactory.html given a definition of a _Persistence Unit_. We cannot go into all the details here. 
104
105 19 Henning Blohm
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]] and [[Sample-jta-spring]]). 
106 13 Henning Blohm
107 19 Henning Blohm
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":http://redmine.z2-environment.net/projects/z2-base/repository/base/revisions/master/entry/org.hibernate/java/src.api/com/zfabrik/hibernate/EntityManagerUtil.java of the module *org.hibernate* in *z2-base.base". This is how it is done in [[Sample-hibernate-basic]].
108 13 Henning Blohm
109 19 Henning Blohm
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":http://redmine.z2-environment.net/projects/z2-samples/repository/revisions/master/entry/com.zfabrik.samples.hibernate-basic.domain/java/src.impl/META-INF/persistence.xml of your domain module. For example, the one in [[Sample-hibernate-basic]] looks like this:
110 13 Henning Blohm
111
<pre><code class="xml">
112
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
113 20 Henning Blohm
        <persistence-unit name="thingies" transaction-type="JTA">
114
                <provider>org.hibernate.ejb.HibernatePersistence</provider>
115
                <jta-data-source>components:com.zfabrik.samples.hibernate-basic.domain/DB
116
                </jta-data-source>
117
                <class>com.zfabrik.samples.hibernate_basic.thingies.Thingy</class>
118
                <exclude-unlisted-classes>true</exclude-unlisted-classes>
119
                <properties>
120
                        <property name="hibernate.dialect" value="org.hibernate.dialect.DerbyDialect" />
121
                        <property name="hibernate.hbm2ddl.auto" value="update" />
122
                        <property name="hibernate.jdbc.batch_size" value="10" />
123
                        <property name="hibernate.cache.use_second_level_cache" value="false" />
124 29 Henning Blohm
                        <property name="hibernate.transaction.jta.platform" value="com.zfabrik.hibernate.Z2JtaPlatform"/>
125
                        <!-- previously to version 2.3 (or Hibernate version 4.3.x) you would use:
126 20 Henning Blohm
                        <property name="hibernate.transaction.manager_lookup_class" value="com.zfabrik.hibernate.TransactionManagerLookup" />
127 29 Henning Blohm
                        -->
128 20 Henning Blohm
                </properties>
129
        </persistence-unit>
130 13 Henning Blohm
</persistence>
131
</code></pre>
132
133
The noteworthy pieces are 
134
135 1 Henning Blohm
# The <jta-data-source/> definition that uses a DataSource JNDI name as discussed above.
136 29 Henning Blohm
# The <property name="hibernate.transaction.jta.platform"/> declaration
137 13 Henning Blohm
138 29 Henning Blohm
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* in the [[Hibernate Add-on]] provides an implementation you can use (it's really simple. See "Z2JtaPlatform":https://redmine.z2-environment.net/projects/z2-addons/repository/z2-addons-hibernate/revisions/master/entry/org.hibernate/java/src.api/com/zfabrik/hibernate/Z2JtaPlatform.java).
139 1 Henning Blohm
140
When not using *com.zfabrik.jta*, the value to specify differ of course. See also [[Sample-jta-plain]].
141
142
h2. Using a full-blown transaction manager
143
144
The sample [[Sample-jta-plain]] and [[Sample-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.
145
146 24 Henning Blohm
h2. Integration of non-Spring Transaction Managers with Spring
147
148
Integration with Spring is yet another subject on its own. Please see the details on [[Sample-spring-hibernate]] for more on that. 
149
150
One important thing to note is that if you use Spring transaction management, it is best to implement transaction demarcation using Spring as well. That is, if you use native JTA interfaces, i.e the UserTransaction object to define begin and end of a transaction, Spring's transaction-scope resource tracking may not function and for example Entity Manager instances provided by Spring will be non-transactional (that is, you will get a new one on every invocation and there will be no managed entities afterwards).
151
152
You can bridge the gap via plain JTA transaction demarcation and Spring's implementation also programmatically. More about that in particular here "programmatic transaction management with Spring":http://static.springsource.org/spring/docs/3.0.x/reference/transaction.html#transaction-programmatic
153
154
h2. Using Spring data sources and the Spring transaction manager
155
156
If you come from a Spring background, you will most likely be familiar to using Spring configured data sources and in particular the Spring transaction manager (e.g. <code>org.springframework.orm.jpa.JpaTransactionManager</code>).
157
158
You are welcome to continue doing so and the same modularization features that apply to all other approaches above apply here as well.
159
160
Please check out the sample [[Sample-springds-hibernate]] for a hands-on example.
161
162 14 Henning Blohm
h2. Integration with Jetty
163
164
The Jetty Web Container that comes with Z2 can be configured to integrate with a transaction manager (see e.g. "Jetty JNDI":http://docs.codehaus.org/display/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.
165
166
When using *com.zfabrik.jta*, having 
167 1 Henning Blohm
168 14 Henning Blohm
<pre><code class="xml">
169 1 Henning Blohm
  <New id="tx" class="org.eclipse.jetty.plus.jndi.Transaction">
170 14 Henning Blohm
    <Arg>
171 1 Henning Blohm
      <New class="com.zfabrik.tx.UserTransaction"/>
172 21 Henning Blohm
    </Arg>
173
  </New>
174 6 Henning Blohm
</code></pre>
175 22 Henning Blohm
176
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.
177 14 Henning Blohm
178 6 Henning Blohm
h2. Summary
179 14 Henning Blohm
180 18 Henning Blohm
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.
181
182
h2. Appendix
183
184
h3. Other entry points
185
186
When your code is not invoked from a Web application, but for example when you call services of yours based on a timer thread, or some scheduler library, or some other protovol implementation, in that case you need to prepare all the context that is prepared by a Web container (for example) otherwise. I.e. you are entering the container business. That is not so bad. It's actually great news that you can do that. Once we have an appropriate Wiki page in place for that and the [[Sample-quartz-spring-worker-process-TBD]] in place there will be more details. 
187
188
In short: The skeleton to prepare _Unit of Work_, _Context Classloader_, as well as the Transaction scope looks something like this:
189
190
<pre><code class="java">
191
ApplicationThreadPool.instance().executeAs(new Callable<Void>() {
192
    public Void call() throws Exception {
193
      return ThreadUtil.cleanContextExceptionExecute(
194
        classloader,
195
        new Callable<Void>() {
196
          public Void call() throws Exception {
197
            return TransactionUtil.run(userTransaction, theActualCallable); 
198
          }
199
        }
200
      );
201
    }
202
  },
203
  false
204
);
205
</code></pre>