Contents
1. Preface
2. System Requirements
3. JTA Overview
4. Configuring TransactionsJTA
5. Programming with TransactionsJTA
6. Appendix A: Answers
7. Appendix B: Complete Examples
8. Appendix C: Getting More out of TransactionsJTA
9. Appendix D: Troubleshooting
10. References
1. Preface
This user guide explains how to use Sun's Java Transaction API (JTA) version 1.0.1 and the Atomikos TransactionsJTA
embedded transaction manager. It is not meant as a general discussion of JTA. However, an overview of JTA is included,
and wherever appropriate there are questions at the end of each chapter that allow you to test your understanding. You are
encouraged to actively try to answer these questions, since they will allow you to get more out if this manual. For more
information on JTA, you are referred to the Sun site (http://java.sun.com), where detailed JTA specifications can be
downloaded for free. Although examples based on JDBC and JMS are used to illustrate the concepts, we consider those
two technologies to fall outside the scope of this manual. Again, the Sun website has more information for the interested
reader. If you don't like to read manuals, then you can take a shortcut and go to the examples in the back. These illustrate
the concepts that are explained in the text with source code of example programs.
2. System Requirements
This guide has been written for Atomikos TransactionsJTA release 1.10 or higher. In order to use the AtomikosJTA system
we recommend that you install and run a Java VM of at least version 1.3. Memory requirements are likely to depend more
on your code than on our software because of the compact nature of the kernel; most modern systems should have more
than enough memory. The libraries that come with TransactionsJTA include most of what you need in order to compile
transactional applications: the API definitions for javax.transaction.*, javax.sql.* and javax.jms.* are included so that
you do not need to get those separately.
NOT included in the TransactionsJTA release are vendor-specific JDBC or JMS implementation libraries. For instance, if
you want to use our transaction service to manage transactions that access your Oracle database, then you need to make
sure that you have the Oracle JDBC classes installed in your classpath, in addition to the TransactionsJTA distribution
classes. Likewise, if you want to use IBM MQSeries for JMS then you need to make sure that the MQSeries libraries are in
your classpath.
3. JTA Overview
Unless explicitly mentioned, the discussion in this chapter is limited to pure JTA: the content of this chapter should apply
for any JTA implementation, not just Atomikos'. Atomikos-specific information is provided in the later chapters of this
manual.
This chapter is a generic JTA overview: it quickly reviews the most important things about JTA that you need to know in
order to use TransactionsJTA. The organization is as follows:
Transactions
What is JTA?
Two-Phase Commit
JTA Components
JTA Interactions
Questions
Transactions
A transaction is a logical unit of work which effects can either be made permanent in their entirety (committed) or
cancelled in their entirety (rolled back). Before a transaction is committed or rolled back, it is active. Active transactions'
effects are typically invisible to other, concurrent transactions. Consequently, only committed transactions' effects are
visible (can you see why?).!
Example
Imagine that you want to publish a customer-related order message through the Java Message Service (JMS) and at the
same time mark the customer's order data in the database as being processed. The message should not be sent unless the
database can be updated and vice versa.!
The concept of transactions requires system-level software support to make these properties hold. A piece of software that
takes care of this is called a transaction manager or transaction service.
Nested Transactions
The nested transaction model is a variant of the normal ('flat') transactional model.
Nested transactions differ in that a subtransaction can be created within
an existing transaction (which becomes the parent transaction). The subtransaction is again a transaction that can be
committed or rolled back. The major differences with normal transactions are in visibility and termination:
Visibility: an active (sub)transaction's effects are visible to its subtransactions (if any). This means that there is
sharing of updates from parent transaction to subtransaction.
Termination: a rolled-back subtransaction does not affect its parent transaction. On the other hand, a committed
subtransaction's effects become part of the parent transaction, and become permanent only after the top-level
transaction (the one without a parent) commits.
What is JTA?
JTA is short for Sun Microsystems' Java Transaction API and is Sun's (low-level) API for creating transactions in Java
and making your data access operations part of those transactions.
The JTA defines how your application can request transactional functionality on the Java platform. JTA is not a product
in itself, but rather a set of Java interfaces. A vendor-specific JTA implementation referred to as a transaction manager
or transaction service (such as TransactionsJTA) is needed to actually use the functionality defined in these interfaces. In
other words, you can program JTA transactions in your application, but you need the implementation classes of a JTA-
compliant transaction manager vendor in order to run your application.
JTA is a standard part of the Java Enterprise (J2EE) platform and every Enterprise JavaBeans (EJB) application server
should also include a JTA implementation. The JTA is said to be low-level because EJB programmers typically don't
access the JTA API directly or explicitly. Rather, the EJB application server makes the appropriate calls behind the scenes.
So given that an EJB server will also give you JTA functionality, why should you consider using Atomikos'
TransactionsJTA? Here are just a few reasons:
EJB servers are often very expensive, and an overkill for many solutions that only need a fraction of the J2EE APIs.
TransactionsJTA provides transactions at a fraction of the cost of a full EJB server.
TransactionsJTA offers more features than defined in the JTA specification.!
TransactionsJTA has better and more functionality than most competitors offer.
TransactionsJTA was designed for very high performance (there is no extra overhead for JTA transactions; local
transactions and JTA transactions can be expected to be equally fast).
With TransactionsJTA you can bring JTA functionality on the J2SE (Java 2 Standard Edition) platform.
Two-Phase Commit
In the previous section we have referred to a JTA implementation as a transaction manager or transaction service. A
transaction is a logical unit of work that either happens completely (in all databases or queues that were accessed by it) or
not at all. The transaction manager is the software module that is responsible for ensuring this property. It does this by
executing a two-phase commit termination protocol that addresses all of the resources that a transaction has used. This
two-phase commit happens behind the scenes of your application: you typically don't notice it.
Let us briefly describe two-phase commit with the previous example still in mind. Two-phase commit works in two
phases: a voting phase and a decision phase.
In the voting (or prepare) phase, the transaction manager will ask both the JMS message queue and the database
whether they can agree with a successful termination or not. Each may return a negative reply, for instance if there
was a time-out which caused the database's work to be rolled back. If one of them replies positively, then it should
make sure it can always make the work permanent (this implies that it can no longer cancel due to an internal time-
out).
After the transaction manager has received all of the replies (also called 'votes') it will make a global decision on the
outcome of the transaction. This decision will depend on the collected replies:
If both replies were positive (meaning that both the JMS and the database can make the work permanent), then
the transaction manager will instruct each to commit.!
If at least one reply is negative (or missing) then a rollback decision is sent to the remaining resource. This
means that the remaining resource cancels (rolls back) the work done for the transaction.
Each resource must have the capability to understand two-phase commit: it needs to reply to a prepare request from
the transaction manager, and be able to rollback (cancel) the work if the transaction manager decides so.
If a resource votes positively during prepare and is then cut off from the transaction manager (for instance, if the
transaction manager crashes) then it does not know what to do. It can not cancel on its own due to the two-phase
commit protocol rules, so it needs to remember the transaction indefinitely. In addition, this restricts concurrent
access by other transactions. In that case, the resource is said to be in-doubt.
This explains why JTA can not be used to make anything transactional: you can only have transactional properties for
applications that access the proper type of resources (those that understand two-phase commit). The fact that a resource can
remain in-doubt and restrict concurrent access is something that has bothered many vendors. To alleviate this restriction, a
practical variant of the two-phase commit protocol includes so-called heuristic decisions: a resource that remains in-doubt
for too long may decide to unilaterally rollback (or commit) the transaction, leading to possible violation of the all-or-
nothing property. We will see more on this later in this chapter.
JTA Components
Here we will review the main components (interfaces) of the JTA specification and briefly discuss their roles. We will not
repeat the definitions for these interfaces; those can be found in the JTA specifications on Sun's site. The packages relevant
to this chapter are javax.transaction and javax.transaction.xa.
TransactionManager
Transaction
Xid
XAResource
Synchronization
UserTransaction
Exceptions
TransactionManager
The transaction manager is where you can create new transactions and set properties (such as timeout) for future
transactions. It also allows your application to retrieve the current transaction, after you have created one. An interesting
point is that this is thread-safe: if you have multiple threads running concurrently, then each thread can create its own
transaction and will be able to retrieve only that transaction which it created. The transaction manager will behave as a
'private' manager for each thread of your application.
begin: this method creates a transaction for the application. When it returns, you will be able to retrieve the
transaction object through getTransaction within the current thread. Atomikos' TransactionsJTA supports nested
transactions, meaning that a transaction can be created within another one. This means that for TransactionsJTA,
calling this method twice in the same thread (without commit/rollback in between) will create a nested transaction,
whose final commit will coincide with the commit of the first transaction you created.
commit: this method will try to commit the last transaction that was created for the current thread. Afterwards, the
transaction can no longer be retrieved by getTransaction. For AtomikosJTA, if the last transaction was a
subtransaction then this will trigger the commit of the subtransaction. According to the semantics of nested
transactions, the subtransaction's updates will not be visible or permanent before the top-level transaction to which it
belongs is committed. The commit of a subtransaction will restore the thread association for its parent transaction.
This means that calling getTransaction will again return the parent transaction.
rollback: this method will trigger rollback of the last transaction that was created for the current thread. For
AtomikosJTA, nested semantics apply: if the current transaction is a subtransaction, then the rollback will not affect
the parent transaction: work done within the parent is not automatically lost by rolling back the subtransaction. As
with commit, this method changes the transaction-association for the thread. For a top-level transaction, this leaves
the current thread without a transaction. For a subtransaction, this method restores the thread association for the
parent transaction.
getTransaction: this method returns the transaction object for the calling thread, or null if there is no active
transaction. The transaction object is needed in order to add work to it: all the work that needs to be part of this
transaction must be explicitly added to it (more on that below).
setTransactionTimeout: this is to set the timeout of future transactions. A timeout indicates the time a transaction is
allowed to be active before it is automatically rolled back by the transaction manager.
getStatus: allows you to retrieve the status of the current transaction.
setRollbackOnly: see Transaction.
suspend: this method is useful if an active transaction exists, but you need to start a new transaction that is
independent. By suspending the current transaction, you dissociate it from the current thread and are free to begin a
new one, whose commit or rollback will not affect the current transaction. If you want to have another thread
continue the current transaction then this method can be used (in combination with resume) to 'pass on' the
transaction to another thread.
resume: this method (re-)associates the calling thread with an existing transaction (typically one that was suspended
first). If you continue a transaction in a different thread, then that thread should call this method with the transaction
as an argument. If you have done some intermediate work in a different transaction, then this method can be called
to resume the original transaction.
Transaction
The transaction interface allows manipulation of an active transaction. The most important role of this interface is to add
work to the scope of the transaction, thereby making the outcome of the work depend on the outcome of the transaction.
The functionality of the transaction interface is discussed below.
enlistResource: this method adds work to the transaction. The required argument is of type XAResource, which is
an interface for resources that understand two-phase commit. By enlisting an XAResource, the work that it represents
will undergo the same outcome as the transaction. If different resources are enlisted, then their outcome will be
consistent with the transaction's outcome, meaning that either all will commit or all with rollback.
delistResource: this method indicates that the application stops using the XAResource for this transaction. The
XAResource is essentially a connection to the underlying data source, and this method notifies the transaction
manager that the connection becomes available for two-phase commit processing.
There are two special cases: if a flag value of TMSUSPEND is given as a parameter, then the method call merely
indicates that the application is temporarily done and intends to come back to this work. This merely serves for
internal optimizations inside the data source. You should call this method if the transaction is being suspended.
Coming back to such a suspended work's context is done by calling enlistResource again, with the same XAResource.
The second special case is when TMFAIL is supplied as argument. This can be done to indicate that a failure has
happened and that the application is uncertain about the work that was done. In this case, commit should not be
allowed, because there is uncertainty about the contents of the transaction. For instance, if a SQLException occurs
during a SQL update, then the application can not know if the update was done or not. In that case, it should delist
the resource with the TMFAIL flag, because committing the transaction would lead to unknown effects on the data;
this could lead to corrupt data.
getStatus: this method returns the status of the transaction.
commit: same as TransactionManager.commit(). This method should not be called randomly: first, every
XAResource that was enlisted should also be properly delisted. Otherwise, XA-level protocol errors can occur.
rollback: same as TransactionManager.rollback(). As with commit, this method should not be called randomly: first,
every resource that was enlisted should also be delisted. Otherwise, XA-level protocol errors can occur.
setRollbackOnly: mark the transaction so that it can not commit. This method is provided to allow application code
to prevent the transaction from committing, without the requirement to call rollback directly. There are good reasons
for this: the rollback should happen after proper delisting of all resources and therefore is not something that happens
randomly. This method, however, can be called at any time when the transaction is active.
registerSynchronization: this method adds a callback for third-party notifications about two-phase commit outcome.
Xid
This interface is important for the communication between the transaction manager and the system behind the
XAResource. The XAResource is essentially a connection to that system, and many different transactions can use the same
connection. Therefore each time the transaction manager wants to begin or end a transaction, it needs to use an identifier
that the system behind understands and that identifies the work of the transaction in question. To this end, one JTA
transaction can have one or even multiple Xid instances associated to it. It is not necessary to completely understand this
mechanism in order to use TransactionsJTA, so it will not be discussed in more detail here.
XAResource
The XAResource is the transaction manager's connection to the data source. For each application-level connection, an
XAResource is needed to make the application's work through that connection part of a JTA transaction. The details of the
XAResource are not important for TransactionJTA, so we will not discuss them any further.
Synchronization
This interface is a means to register an application-level callback; it allows the application to be notified upon two-phase
commit events. You can use this functionality by implementing this interface in your application.
Note: synchronizations are not persistent; after a crash, any recovered transactions' synchronizations will be lost.
beforeCompletion: this method is called before the transaction will start its commit. A typical usage of this method
is to write pending updates to the database.
afterCompletion: this method is called after the commitment was done, and indicates whether it was successful or
not.
UserTransaction
This interface is a simple and restricted version of the JTA functionality. It is the typical application-level transaction
service handle in EJB. You can use this interface to expose only a subset of JTA functionality to the application code.
Exceptions
There are some specific exceptions in JTA that are worth mentioning: those that concern the heuristic terminations. Since
they are not really made clear in the JTA specification, we will mention something about them here. Whenever a heuristic
error happens the transaction manager should keep a log entry for the transaction involved, so that a human administrator
can resolve any conflicts. Part of Atomikos' patent applications concern precisely the kind of information that is available
in the logs in these cases.
HeuristicCommitException: if all resources have been in-doubt for too long, they may have committed the
transaction although all replied positively during the prepare of two-phase commit. If the transaction manager later
re-establishes contact and instructs the resources to rollback then this exception will be thrown to the application. It
indicates an anomaly in the transaction's outcome, where all resources involved have chosen to commit
heuristically, because all were left in-doubt. If you get this exception, it means that the entire transaction has been
committed, although rollback was desired.
HeuristicRollbackException: all resources have decided to rollback although the final decision of the transaction
manager was to commit. This is similar to the previous case; this time it means that the entire transaction has in fact
been rolled back whereas the desired outcome was commit.
HeuristicMixedException: this is the most complex error, where some of the resources may have committed and
others have rolled back. It hints that the transaction's effects are only partial; this is a clear violation of transactional
semantics. Remember, more information should be in the logs.
JTA Interactions
This section hightlights some typical JTA interactions for JDBC data sources. For other resources such as JMS queues,
most things are the same except for the way the XAResources are to be retrieved.
Active Transaction
Transaction Commit
Transaction Rollback
Transaction Termination with Errors
Active Transaction
The typical interactions for an active JTA transaction are shown below. Note that the only thing you have to provide is the
Application, and the Connection Manager if you don't use the Atomikos connection pools.
Please note a very important point when using connection pools: the connection manager will only be able to delist a
resource when it is informed about the application-level close operation on the JDBC connection. This means that you
should always properly close the connections from the pool; this should be done in the finally-part of a try{...}finally{...}
block. Opening the connection belongs in the try-part.
Transaction Commit
A possible rollback scenario is shown below: the application requests commit, but one of the XAResources has timed out
and rolled back before it is asked to prepare. The result is rollback, and an application-level exception (since commit was
requested).
A possible heuristic scenario is shown below: the application requests commit, but one of the XAResources becomes
unreachable after it is asked to prepare. The result is heuristic rollback, and by the time the transaction manager re-
establishes contact commit fails with a heuristic error. An application-level heuristic mixed exception is thrown (since the
other two XAResources did commit, parts have been committed and other parts have not).!
Questions
Question 1
Consider the two-phase commit protocol and the example in the text: an update in a database and a message being
published in JMS, as part of one transaction. Can't you solve the problem of reaching the same outcome for both parts by
controlling the order in which you execute each one? For instance, why bother controlling the outcome of a database
update if your application knows that it succeeded already?!
Question 2
Imagine the following scenario: an application is using a JTA implementation to manage transactions that access two JDBC
databases, say, DBa and DBb. The application has updated both of them and is in the course of committing the transaction.
As part of that commit processing, the transaction manager has received positive replies from both databases when it asked
them to prepare and hence it decides to commit. However, it can only notify DBa of this decision: before DBb can be told
about commit, a system crash happens and causes DBb to go down. The rest of the system is not affected because DBb is
running on its own private machine. The transaction manager repeatedly retries to connect to DBb, but after a while it
gives up and throws an exception to the application. What is the exact type of this exception?
Question 3
Which of these methods can be called at any time when a transaction is active: setRollbackOnly or rollback? Why?
Question 4
An application has started a transaction and is in the middle of updating a JDBC database when a SQLException happens.
Should the transaction be committed or rolled back?
Question 5
An application is listening on incoming remote method invocation (RMI) request. An incoming requests is executed in
some Java thread according to the virtual machine's internal rules. This thread could be the same one as for a previous
request. The application-level logic for an invocation involves creating a JTA transaction and doing some JDBC work as
well as publishing a JMS message. If you are using a JTA implementation that supports nested transactions, why should
you always make sure that the transaction is terminated (by commit or rollback) before the invocation returns?
4. Configuring TransactionsJTA
Whereas the previous chapter was generic JTA information, this chapter is specific to TransactionsJTA. It concerns the
setup (configuration) of TransactionsJTA in your application.
TransactionsJTA is an embedded transaction service, meaning that it runs inside the same VM as your application. This
optimizes speed and availability of your application.
The configuration file is independent of which type of resources you want to use. It contains general transaction-related
information such as where logfiles are to be kept and what default timeout values are.
The runtime setup is needed to indicate which resources you want to use in your transactions. This is important since it also
indicates which resources are to be recovered during transaction service startup. Because runtime setup is different for JMS
or JDBC data sources, we discuss each separately. We will also see how to add other types of XA-capable resources.
For each type of JDBC and JMS setup there is a complete application with source code in the appendix.
Name the file standalone.prp and put it in the directory where you start your application (assuming you are using a
command-line approach to launch).
Give your file any name and location you like, and specify this as a system property at startup: java -
Dcom.atomikos.icatch.standalone.properties=path_to_your_file ... Note that setting this system property
overrides any standalone.prp configuration data that you might have according to the first approach.
To avoid using a configuration file, you can also use system properties for each of the parameter settings. You can
indicate that this is the case by supplying the following system property at startup: java -
Dcom.atomikos.icatch.standalone.no_file ... In that case, your custom settings need to be supplied as system
properties with the same name as their configuration file equivalents.
The configuration file can contain the parameters shown in the example below. Note that the format should be a valid Java
property-file format.
!#THIS FILE ILLUSTRATES THE DIFFERENT SETTINGS FOR THE TRANSACTION MANAGER
!#UNCOMMENT THE ASSIGNMENTS TO CHANGE THEIR VALUES;
!#VALUES SHOWN NOW ARE THE DEFAULTS
!#set output directory where console file and other files are to be put
!#make sure this directory exists!
!#output_dir = ./
Runtime Configuration
For any application based on TransactionsJTA, we can distinguish the following main steps:
The following code fragment illustrates this and summarizes the information in this chapter:
This chapter is about steps 1, 2, 4 and 6. Step 3 is discussed in the Appendix. Step 5 is the topic of the next chapter, when
we talk about programming with TransactionsJTA. The main runtime configuration of TransactionsJTA is done in steps 1
and 2: there you indicate what resources (data sources) should fall under the custody of the transaction service. This is most
important for recovery.
Registering a RecoverableResource
The interface com.atomikos.datasource.RecoverableResource allows about any data source you can imagine to take part
in transactions. For instance, it is possible to make a transactional file system that implements this interface.
It is important to note that each resource should be given a unique name that identifies the combination (transaction
manager, resource). So if you use the same database or queue in different transactional applications then you need to
make sure that every application uses a unique and different name.
The JTA specification works with the XA protocol for making things transactional, so we have provided some XA-specific
implementations of RecoverableResource for your convenience. The two most useful ones are one for JDBC and one for
JMS transactions. Each of them is discussed in the rest of this chapter.
Before your application exits, you should give the transaction service a chance to perform proper shutdown (closing the
logs, detecting active transactions, ...). You can do this by calling the UserTransactionService's shutdown method. This
method expects one boolean argument indicating whether to force shutdown or not. If true, then shutdown proceeds even if
there are active transactions. Forcing shutdown can sometimes lead to increased risk for heuristics. Note: shutdown(false)
will block until any remaining active transactions are finished.
This type of integration is of interest to application-server vendors who are likely to have their own connection pooling
support. If you are not going to use Atomikos' connection pooling then setup is done by registering an instance
of com.atomikos.jdbc.JdbcTransactionalResource with the TSInitInfo instance.
As soon as you have created an instance of JdbcTransactionalResource, you can register it with TSInitInfo. Later, after
startup, you will be able to run transactions that include data accesses to the underlying database (as explained in the next
chapter). The following code fragment illustrates JDBC setup for XA integration.
!...
!//database-specific setup of an XADataSource;
!//see your favorite database docs for details
!//on where and how to create the data source instance
!XADataSource xads = ...
Use this approach if you don't want to write XA-level integration code. If you are using Atomikos' Connection Pooling
then you don't need to explicitly create a JdbcTransactionalResource. Rather, you create
an instance of Atomikos' com.atomikos.jdbc.JtaDataSourceImp to get connections from. As part of that process, a
JdbcTransactionalResource will be created for you. The class JtaDataSourceImp implements the javax.sql.DataSource
interface, so it is JDBC-compatible. The creation of a JtaDataSourceImp is a three-step process:
!...
!//database-specific setup of an XADataSource;
!//see your favorite database docs for details
!//on where and how to create the data source instance
!XADataSource xads = ...
Note that an additional constructor is available that allows you to supply a custom XidFactory; this is needed only if the
XADataSource will not accept arbitrary Xid formats.
At creation time, this connection factory has automatically created a JdbcTransactionalResource for you. You can (and
should) register this resource in the TSInitInfo instance:
!...
!TransactionalResource res = factory.getTransactionalResource();
!info.registerResource ( res );
!...
!...
!//how large is the connection pool?
!int poolsize = 5;
!//how many seconds should connections be allowed inactive?
!int ctimeout = 30;
!//how many seconds before a statement times out?
!int stimeout = 30;
!com.atomikos.jdbc.JtaDataSourceImp jtads =
!!new JtaDataSourceImp ( factory , poolsize , ctimeout , stimeout );
!info.registerResource ( res );
!...
You can now use the JtaDataSourceImp in your application to access pooled connections. The picture below summarizes
all of the JDBC pooling setup.
NOTE: for JMS, currently only queuing operations are readily supported by TransactionsJTA. If you do need to
incorporate the publish-subscribe model in your transactions then see the following section, Configuring for Other
XAResource Types.
JMS Integration at the XA-Level
This is the more complicated way of combining TransactionsJTA with your JMS application. The complexity appears at
the programming level, not at the configuration level.
In order to make a JMS (queuing) system transactional, you need to create the proper RecoverableResource to register with
the transaction service. For JMS queues, the appropriate class
to use is com.atomikos.datasource.xa.jms.JmsTransactionalResource. The two constructors you can use are the
following:
Most of the time, the first constructor will be the one you need. Once created, the resource can be registered with the
transaction service.!The following code fragment illustrates this.
!...
!//get an XAConnectionFactory for the queuing system, cf. your JMS provider's documentation
!XAConnectionFactory factory = ...
!//create a JmsTransactionalResource
!JmsTransactionalResource resource =
!!new JmsTransactionalResource ( "MyUniqueName" , factory );
!//add the resource to the info object
!info.registerResource ( resource );
!...
Use this approach if you don't want to use XA-level integration. For your convenience, a JMS adapter framework is
included with TransactionsJTA. This framework hides the extra complexities of XA-related operations from your
application. Externally, it offers the same set of interfaces as any JMS (1.0.2b) queuing system with the difference that
everything works in JTA transactions.
Instead of directly creating a JmsTransactionalResource (as in the previous case), you now create a
com.atomikos.datasource.xa.jms.JtaQueueConnectionFactory. This is an implementation of
javax.jms.QueueConnectionFactory that performs XA-related tasks behind the scenes. From this specialized factory, you
can then retrieve the JmsTransactionalResource instance (which is created for you during initialization).
Usually you will only need the first constructor. Once created, this JtaQueueConnectionFactory also has the resource you
need to add to the transaction service. The following code fragment illustrates this.
!...
!//get an XAConnectionFactory for the queueing system, cf. your JMS provider's documentation
!XAConnectionFactory factory = ...
!//create the JtaQueueConnectionFactory
!JtaQueueConnectionFactory jtaConnFactory =
!!new JtaQueueConnectionFactory ( "MyResourceName" , factory );
!//get the corresponding JmsTransactionalResource
!JmsTransactionalResource resource =
!!jtaConnFactory.getTransactionalResource();
If you need JTA transactions that access systems other than JDBC or JMS queues then you may need to implement your
own adapter class, by extending our com.atomikos.datasource.xa.XATransactionalResource class.
As the previous diagram shows, the XATransactionalResource is an abstract class with generic functionality already in
place. The diagram only shows the methods that are relevant for you:
Questions
Question 1
Suppose you are doing an Enterprise Application Integration (EAI) project that connects a JDBC database, a JMS queue
and a JCA (Java Connector API) adapter to a legacy system. Which of the following does not have out-of-the-box support
in TransactionsJTA?
Question 2
If you don't have a configuration file and don't set system properties related to the configuration, where will the transaction
service write log files?
Question 3
In the configuration file, there is a parameter called checkpoint_interval. If you increase this parameter's value, then what
happens?
Question 4
Are the following statements true or false? Suppose there is a back-end JDBC database that is not registered with the
transaction service by means of a corresponding resource. In that case,
1. The transaction service will not perform recovery for that JDBC database.
2. The JTA transactions you create can not include accesses to that JDBC database.
!...
!import com.atomikos.icatch.UserTransactionService;
!import com.atomikos.icatch.standalone.StandAloneConfiguration;
!import javax.transaction.*;
!...
!//get the main application-level handle to the transaction service
!UserTransactionService uts =
!!StandAloneConfiguration.getUserTransactionService();
!//retrieve a handle to the JTA transaction manager
!TransactionManager tm = uts.getTransactionManager();
!//rollback flag, true as soon as error happens
!boolean rollback = false;!
!try {
!!rollback = false;
The rest of this chapter discusses programming in more detail, according to the following outline.
Beginning a Transaction
JDBC Transactions
XA-Level Integration
Integration with Atomikos Connection Pools
JMS Transactions
XA-Level Integration
Integration with Atomikos JMS/JTA Adapters
Transactions for Other XAResource Types
Terminating a Transaction
Questions
Complete example programs for JDBC and JMS programming with TransactionsJTA are provided in the appendix.
Beginning a Transaction
Beginning a transaction is done by calling the TransactionManager.begin() method. The previous chapter explained how to
initialize the transaction service by calling its init() method with the initialization object. From that moment on, a JTA
Transaction Manager is available inside your application's virtual machine and can be retrieved through the
UserTransactionService interface.
JDBC Transactions
How to include JDBC access in a JTA transaction depends on the options you made during configuration.
XA-Level Integration
If you chose for XA-level integration then more things will need to be done by your application (either inline with the
code as shown here, or behind the scenes in custom connection pools). The following code fragment elaborates on how to
provice XA-level transaction integration to a JDBC database. It is based on the code fragment at the beginning of this
chapter.
!...
!//we assume you have gotten an instance of XADataSource already; see the previous chapter
!XADataSource xads = ... //vendor-specific
!//get an XAConnection from the XA datasource
!XAConnection xaconn = xads.getXAConnection();
!}
!catch ( Exception e ) {
!!//rollback for safety
!!rollback = true;
!!throw e;
!}
!finally {
!!//ALWAYS make sure that the transaction is terminated!
!!if ( rollback )
!!!tm.rollback();
!!else
!!!tm.commit();
!}
Note that this is a simplified example showing only the most essential operations. In practice, you should make sure that
delistResource is called even in case of exceptions during JDBC access (with the TMFAIL flag in that case). Application-
server vendors with their own connection pools typically do this behind the scenes.
If you don't want to implement your own xaconnection management then it is probably better to use the Atomikos pooling
utilities. This section assumes that you have setup and configured TransactionsJTA to use the supplied pooling facility. In
other words, you have created a JtaDataSourceImp and registered the corresponding JdbcTransactionalResource.
!...
!//we assume you have created a JtaDataSourceImp at startup, as described in chapter 4
!JtaDataSourceImp jtads = new JtaDataSourceImp ( ... );
!...
!//rollback flag, true as soon as error happens
!boolean rollback = false;!
!try {
!!rollback = false;
!}
!catch ( Exception e ) {
!!//rollback for safety
!!rollback = true;
!!throw e;
!}
!finally {
!!//ALWAYS close the connection to return it to the pool!
!!if ( conn != null )
!!!conn.close();
In this case programming is according to the normal javax.sql.DataSource way. As can be seen, this is very simple. The
important thing is to always close a connection; this will return it to the pool and also do the delistResource behind the
scenes. After that, commit or rollback can be done.
NOTE: the getConnection() operation will only work inside a JTA transaction. Also note that the JtaDataSourceImp class
implements the javax.sql.DataSource interface.
JMS Transactions
For JMS, we will again make the distinction between XA-level and the simpler integration through adapters.
XA-Level Integration
Here, it is assumed that you have done the corresponding configuration tasks for JMS with XA-level integration. For this
mode, you need to work with XA classes and perform the enlistResource and delistResource operations yourself, either
inline or behind the scenes through utility classes that you create. The following illustrates this.
!...
!//we assume you have created an XAQueueConnectionFactory as described in chapter 4.
!XAQueueConnectionFactory factory = ...
!//create an XAQueueConnection
!XAQueueConnection xaconn = factory.createXAQueueConnection();
!//create an XAQueueSession
!XAQueueSession xasession = xaconn.createXAQueueSession();
!Tranaction tx = null;
!try {
!!rollback = false;
!!//create a message
!!Message message = session.createTextMessage();
!}
!catch ( Exception e ) {
!!//rollback for safety
!!rollback = true;
!!throw e;
!}
!finally {
!!//ALWAYS make sure that the transaction is terminated!
!!if ( rollback )
!!!tm.rollback();
!!else
!!!tm.commit();
!}
The simpler way of integrating JMS (1.0.2b) with your JTA transactions is through the Atomikos JMS/JTA adapters. Here
we assume that you have done setup and configuration as required for this paradigm. This means that you have created a
JtaQueueConnectionFactory. The typical application-level tasks are shown below.
!...
!//we assume you have created a JtaQueueConnectionFactory during setup
!JtaQueueConnectionFactory factory = ...
!try {
!!rollback = false;
This looks exactly like regular JMS queue manipulation, with the exception that everything is transactional.
Atomikos JMS adapters require a transaction for a send or receive; trying to send or receive outside a transaction will fail.
Also, there are no clear transactional semantics for the MessageListener interface (the JMS specifications are not clear with
respect to this issue).
Terminating a Transaction
The termination of a transaction is done by calling either the rollback or commit method. Termination is extremely
important, to avoid confusion with later transactions started in the same thread (see our JTA discussion on nested
transactions).
Questions
Question 1
For each of the following, indicate whether the application code is portable across multiple vendors' JTA.
1. JDBC-XA
2. JDBC-DataSource
3. JMS-XA
4. JMS-Adapters
6. Appendix A: Answers
Chapter 3: Answers
Question 1
You can not control the joint outcome of a database update and a JMS message publication by merely ordering the
executions. For instance, if you do a successful database update first and then try to send a JMS message, then what do you
do if the JMS part fails? You could argue that the JDBC and the JMS allow you to explicitly control commit and rollback,
but that does not change the real problem: in what order should the commits of the database and the message send be done?
If you commit the database first, there is no way to go back if the later JMS commit fails. A similar argument shows that
the JMS can not be committed first either. Controlling the order of executions or the order of commits is not a solution;
that is why two-phase commit is used.
Question 2
The exception is of type HeuristicMixedException. The transaction manager is cut off from the in-doubt database, so it
does not know whether the database will make a heuristic decision or not, and if it does then it could be either commit or
rollback. A violation of the requirement that all resources have the same outcome is possible.
Question 3
The method setRollbackOnly can be called almost anytime. The method rollback should only be called after all resources
that were enlisted have also been delisted accordingly. Otherwise, XA-level errors may occur during rollback.
Question 4
If a SQLException happens in a database update, there is a possibility that the database state for the active transaction is
corrupt or does not correspond to what is expected from the point of view of the application. The transaction should be
rolled back to make sure that the database is restored to the previous and correct state.
Question 5
The JTA transaction manager associates the thread to the transaction you create. This means that if you call
TransactionManager.begin() at the beginning of the method invocation then the executing thread has a JTA transaction. If
you don't terminate this transaction then it will become a pending active transaction, subject to JTA rollback after timeout
(and this will happen). Before the timeout, other requests may be executed in the same thread. If that happens then the
second request's TransactionManager.begin() will create a subtransaction of the still pending transaction. So even if the
second invocation calls commit, this will be a commit of a subtransaction, whose effects will not become permanent until
the parent transaction commits. But the latter will not happen because the parent is a pending active transaction that will be
rolled back if it times out. This is illustrated in the picture below.
Chapter 4: Answers
Question 1
The JCA does not have out-of-the-box support: you need to subclass
com.atomikos.datasource.xa.XATransactionalResource in order to use the legacy system in your JTA transactions.
Question 2
The logs will be written in the directory where you start your application. See the sample configuration file listing, which
shows the default values. These are the values used if no other information is available.
Question 3
The average log file size will be larger. The checkpoint interval is the number of writes to the sequential log file before
this file is cleaned up, so if this number is higher then the average log file size will increase as well. The cleanup
encompasses purging the log by deleting information about terminated transactions.
Question 4
Both statements are true: no recovery will happen on behalf of the transaction service, and no JTA-transactional accesses
will be possible. You need to register the resource in order to do that.
Chapter 5: Answers
Question 1
If we disregard the configuration code (by separating it from the application code) then the following can be said about
portability:
The configuration code is not portable because there is no specification on how to configure and setup JTA.
package examples.jdbc.xa;
import javax.transaction.*;
import javax.transaction.xa.*;
import javax.sql.*;
import java.sql.*;
import com.atomikos.icatch.*;
import com.atomikos.icatch.standalone.*;
import com.atomikos.datasource.*;
import com.atomikos.datasource.xa.*;
import com.atomikos.jdbc.*;
import COM.cloudscape.core.DataSourceFactory;
/**
*Copyright © 2002, Guy Pardon. All rights reserved.
*
*A simple program that uses XA-level integration with
*TransactionsJTA. Although only one database is
*accessed, it shows all important steps for programming
*with TransactionsJTA.
*
*Usage: java XaAccount account_number operation [amount]
*where:
*account number is an integer between 0 and 99
/**
*Initialize the TM, and setup DB tables if needed.
*/
/**
*Shutdown the TM and the datasource.
*/
//
//THE CODE BELOW SHOULD NOT BE CHANGED;
//IT SHOULD WORK ON ANY JDBC COMPLIANT SYSTEM
//
/**
*Gets the xa datasource instance.
*
*@return XADataSource The data source.
*/
/**
*Utility method to start a transaction and
*get a connection.
*This method does all XA related tasks
*and should be called within a transaction.
*@return XAConnection The xa connection.
*/
/**
*Utility method to close the connection and
*terminate the transaction.
*This method does all XA related tasks
*and should be called within a transaction.
*When it returns, the transaction will be terminated.
*@param xaconn The xa connection.
*@param error Indicates if an error has
*occurred or not. If true, the transaction will be rolled back.
*If false, the transaction will be committed.
*/
if ( error )
tm.rollback();
else
tm.commit();
try {
xaconn = getConnection();
Statement s = xaconn.getConnection().createStatement();
String query = "select balance from Accounts where account='"
+"account"+account+"'";
ResultSet rs = s.executeQuery ( query );
if ( rs == null || !rs.next() )
throw new Exception ( "Account not found: " + account );
res = rs.getLong ( 1 );
s.close();
}
catch ( Exception e ) {
error = true;
throw e;
}
finally {
closeConnection ( xaconn , error );
}
return res;
}
try {
xaconn = getConnection();
Statement s = xaconn.getConnection().createStatement();
String query = "select owner from Accounts where account='account"
+ account+"'";
ResultSet rs = s.executeQuery ( query );
if ( rs == null || !rs.next() )
throw new Exception ( "Account not found: " +account );
res = rs.getString ( 1 );
s.close();
}
catch ( Exception e ) {
error = true;
throw e;
}
finally {
closeConnection ( xaconn , error );
}
return res;
}
try {
xaconn = getConnection();
Statement s = xaconn.getConnection().createStatement();
}
public static void main ( String[] args )
{
try {
//test if DB data has to be created
setup();
//get operation
String op = args[1];
if ( op.equals ( "balance" ) ) {
long bal = getBalance ( accno );
System.out.println ( "Balance of account " + accno + " is: " + bal );
}
else if ( op.equals ( "owner" ) ) {
String owner = getOwner ( accno );
System.out.println ( "Owner of account " + accno + " is: " + owner );
}
else {
//get amount
if ( args.length< 3 ) {
System.err.println ( "Missing argument: amount." );
System.exit ( 1 );
}
int amount = new Integer ( args[2] ).intValue();
if ( op.equals ( "withdraw" ) )
withdraw ( accno , amount );
else withdraw ( accno , amount * (-1) );
}
shutdown();
}
catch ( Exception e ) {
e.printStackTrace();
}
package examples.jdbc.pooled;
import javax.transaction.*;
import javax.transaction.xa.*;
import javax.sql.*;
import java.sql.*;
import com.atomikos.icatch.*;
import com.atomikos.icatch.standalone.*;
import com.atomikos.datasource.*;
import com.atomikos.datasource.xa.*;
import com.atomikos.jdbc.*;
import COM.cloudscape.core.DataSourceFactory;
/**
*Copyright © 2002, Guy Pardon. All rights reserved.
*
*A simple program that uses JDBC-level integration with
*TransactionsJTA. Although only one database is
*accessed, it shows all important steps for programming
*with TransactionsJTA.
*
*Usage: java PooledAccount account_number operation [amount]
*where:
*account number is an integer between 0 and 99
TransactionManager tm = uts.getTransactionManager();
tm.setTransactionTimeout ( 60 );
/**
*Shutdown the TM and the datasource.
*/
//
//THE CODE BELOW SHOULD NOT BE CHANGED;
//IT SHOULD WORK ON ANY JDBC COMPLIANT SYSTEM
//
/**
*Gets the xa datasource instance.
*
*@return XADataSource The xa data source.
*/
/**
*Utility method to start a transaction and
*get a connection.
*This method should be called within a transaction.
*@return Connection The connection.
*/
conn = ds.getConnection();
return conn;
/**
*Utility method to close the connection and
*terminate the transaction.
*This method does all XA related tasks
*and should be called within a transaction.
*When it returns, the transaction will be terminated.
*@param conn The connection.
*@param error Indicates if an error has
*occurred or not. If true, the transaction will be rolled back.
*If false, the transaction will be committed.
*/
try {
conn = getConnection();
Statement s = conn.createStatement();
String query = "select balance from Accounts where account='"
+"account"+account+"'";
ResultSet rs = s.executeQuery ( query );
if ( rs == null || !rs.next() )
throw new Exception ( "Account not found: " + account );
res = rs.getLong ( 1 );
s.close();
}
catch ( Exception e ) {
error = true;
throw e;
}
finally {
closeConnection ( conn , error );
}
return res;
}
try {
conn = getConnection();
Statement s = conn.createStatement();
String query = "select owner from Accounts where account='account"
+ account+"'";
ResultSet rs = s.executeQuery ( query );
if ( rs == null || !rs.next() )
throw new Exception ( "Account not found: " +account );
res = rs.getString ( 1 );
s.close();
}
catch ( Exception e ) {
error = true;
throw e;
}
finally {
closeConnection ( conn , error );
}
return res;
}
try {
conn = getConnection();
Statement s = conn.createStatement();
String sql = "update Accounts set balance = balance - "
+ amount + " where account ='account"+account+"'";
s.executeUpdate ( sql );
s.close();
}
catch ( Exception e ) {
error = true;
throw e;
}
finally {
closeConnection ( conn , error );
//get operation
String op = args[1];
if ( op.equals ( "balance" ) ) {
long bal = getBalance ( accno );
System.out.println ( "Balance of account " + accno + " is: " + bal );
}
else if ( op.equals ( "owner" ) ) {
String owner = getOwner ( accno );
System.out.println ( "Owner of account " + accno + " is: " + owner );
}
else {
//get amount
if ( args.length < 3 ) {
System.err.println ( "Missing argument: amount." );
System.exit ( 1 );
}
int amount = new Integer ( args[2] ).intValue();
if ( op.equals ( "withdraw" ) )
withdraw ( accno , amount );
else withdraw ( accno , amount * (-1) );
}
shutdown();
}
catch ( Exception e ) {
e.printStackTrace();
}
}
Example 3: XA-Level JMS Integration
The third example application is a JMS-based program with XA-Level integration with TransactionsJTA. It assumes a
SONICMQ installation is present on your system.
package examples.jms.xa;
import javax.transaction.*;
import javax.transaction.xa.*;
import javax.jms.*;
import com.atomikos.icatch.*;
import com.atomikos.icatch.standalone.*;
import com.atomikos.datasource.*;
import com.atomikos.datasource.xa.*;
import com.atomikos.datasource.xa.jms.*;
import progress.message.jclient.QueueConnectionFactory;
/**
*Copyright © 2002, Guy Pardon. All rights reserved.
*
*An example of a queue application using XA integration with
*TransactionsJTA. Although only one queue is accessed, all the
*essential operations are shown.
*
*/
/**
*Get the transaction manager.
*@return TransactionManager The tm.
*/
/**
*Utility method to process XA operations
*before doing send or receive. Also starts a transaction.
*@return XAQueueSession The xa queue session.
*
*/
/**
*Utility method to process XA operations at end of send/receive.
*This method also terminates the transaction.
*@param session The XA session.
*@param error True iff rollback required.
*/
/**
*Receive from queue.
*@return String The text of the message found.
*/
/**
*Send to the queue.
*@param text The text of the message to be sent.
*/
}
catch ( Exception e ) {
e.printStackTrace();
error = true;
throw e;
}
finally {
giveXAQueueSession ( xasess , error );
}
}
//check arguments
if ( args.length == 0 ) {
System.err.println ( "Arguments required: operation [message]" );
System.err.println ( "where operation is send or receive" );
System.err.println ( "and message is the text in case of send" );
System.exit ( 1 );
}
}
else if ( operation.equals ( "receive" ) ) {
String text = receive();
System.out.println ( "Received text: " + text );
}
else {
System.out.println ( "Unknown operation: " + operation );
}
package examples.jms.adapter;
import javax.transaction.*;
import javax.transaction.xa.*;
import javax.jms.*;
import com.atomikos.icatch.*;
import com.atomikos.icatch.standalone.*;
import com.atomikos.datasource.*;
import com.atomikos.datasource.xa.*;
import com.atomikos.datasource.xa.jms.*;
import progress.message.jclient.QueueConnectionFactory;
/**
*Copyright © 2002, Guy Pardon. All rights reserved.
*
*An example of a queue application using adapter integration with
*TransactionsJTA. Although only one queue is accessed, all the
*essential operations are shown.
*
*/
/**
*The adapter integration setup.
*/
/**
*Perform shutdown.
*/
/**
*Get the transaction manager.
*@return TransactionManager The tm.
*/
/**
*Utility method that get the session and starts a transaction.
*@return QueueSession The queue session.
*
*/
return session;
}
/**
*Utility method to process operations at end of send/receive.
*Terminates the transaction.
*@param session The session.
*@param error True iff rollback required.
*/
/**
*Receive from queue.
*@return String The text of the message found.
*/
/**
*Send to the queue.
*@param text The text of the message to be sent.
*/
package com.atomikos.datasource.xa.jms;
import com.atomikos.datasource.*;
import com.atomikos.datasource.xa.*;
import javax.transaction.*;
import javax.transaction.xa.*;
import java.util.*;
import javax.jms.*;
/**
*A transactional resource implementation for JMS queues.
*
*Copyright © 2002, Guy Pardon, Atomikos. All rights reserved.
*/
/**
*Create a new instance.
*@param name The unique resource name.
*@param factory The xa connection factory to use.
*/
public JmsTransactionalResource (
String name ,
XAQueueConnectionFactory factory )
{
super ( name );
factory_ = factory;
conn_ = null;
}
/**
*Create a new instance, but one that
*requires a specific Xid format. This may be
*necessary for some JMS implementations that require
*their own format.
*@param name The unique resource name.
*@param qFactory The queue connection factory.
*@param xidFactory The factory for Xid instances.
*/
public JmsTransactionalResource (
String name ,
XAQueueConnectionFactory qFactory,
XidFactory xidFactory )
{
super ( name , xidFactory );
factory_ = qFactory;
conn_ = null;
}
/**
*Implements the functionality to get an XAResource
*handle. This method is called by the superclass
*whenever necessary. It is the most important method of
*this class.
*@return XAResource The XAResource instance.
*/
if ( conn_ != null ) {
try {
conn_.close();
}
catch ( Exception err ) {
//happens if connection has timed out
//which is probably the case
}
}
try {
//JMS-specific way of obtaining an XAResource
//instance that connects to the back-end JMS system
conn_ = factory_.createXAQueueConnection();
XAQueueSession session = conn_.createXAQueueSession();
res = session.getXAResource();
}
catch ( JMSException jms ) {
Stack errors = new Stack();
errors.push ( jms );
throw new ResourceException (
"Error in getting XA resource" , errors );
}
return res;
/**
*Overrides default close to include closing any open
*connections to the Queue infrastructure.
*/
Heuristic exceptions can be well-documented with their effects on the business-level: if you add an application-level
comment for each interaction with a data source or JMS queue, then the occurrence of a heuristic exception will allow the
corresponding comments to be retrieved from the logs. The result is that heuristic exceptions include their application-level
effects, thereby easing administration. The comment's interface type is discussed in this section; the later sections show
how to add them to the interactions (and to the logs).
Instead of merely getting a connection from a JtaDataSourceImp (as done with regular DataSource instances), you can use
the getConnection method with one extra parameter that supplies a HeuristicMessage. This will add the message to the logs
in case of JDBC.
You have to use the JDBC with Atomikos connection pools for this approach to work.
By performing a cast to this interface upon calling QueueSession.createSender(queue) you can gain access to the extra
functionality.
You have to use the JMS with Atomikos' JMS adapters for this approach to work.
By performing a cast to this interface upon calling QueueSession.createReceiver(queue) you can gain access to the extra
functionality.
You have to use the JMS with Atomikos' JMS adapters for this approach to work.
!..
!//create a log administrator with given title and (in our case)
!//indicate that it is not running as the main window
!//of the application
!LocalLogAdministrator admin =
!!new LocalLogAdministrator ( "Transaction Administrator" , false );
!info.registerLogAdministrator ( admin );
!uts.init ( info );
!...
Through the menu item labeled Show Active Transactions... you can create a view window that shows the transactions
that are in their 2-phase-commit at that moment. There are a few important things to notice about this window:
Transactions created after this window was opened will not be shown. This is to prevent high throughput from
causing many screen updates and thereby cluttering the overview.
If any transactions appear, then their states will be refreshed periodically (about every 5-10 seconds).
For lower throughputs, this window will usually be empty. Only problematic transactions are likely to show up,
because the two-phase commits happen in a relatively short time span.
If you are running the administrator as the main window of your application, then choosing Exit from the main menu will
also shutdown the transaction service for you.
If you are using an instance of LocalLogAdministrator that is not the main window (as indicated in the constructor
arguments) then your application will not exit unless you explicitly call the System.exit() method. This is normal
behaviour caused by the Swing event thread that will keep runnig even after you have called shutdown.
JTA UserTransaction
The TransactionsJTA release also comes with a UserTransaction
implementation: com.atomikos.icatch.jta.UserTransactionImp. This class has a public no-argument constructor and is
referenceable through JNDI.
9. Appendix D: Troubleshooting
This appendix contains some help on problems that you might encounter when using TransactionsJTA. The set of problems
here is fairly 'stable' in that they are not bugs but merely consequences of using TransactionsJTA in a way it is not intended
to. Usually there is an easy solution. If you have a problem not listed here then please contact support@atomikos.com.
During the execution of a transaction, a delistResource or another operation that accesses the transaction (such as a send/
receive in JMS or a getConnection/close in JDBC) fails with a message saying (among other things):
Wrong state for addParticipant: TERMINATED
Explanation
The work you were doing inside the transaction has taken too long, and the transaction has been rolled back in the
meantime.
Suggestion
Increase the transaction timeout by calling the TransactionManager's setTransactionTimeout method. Do this before you
start the transaction.
Epoch Overflow
Problem Description
The transaction service throws a RuntimeException with the following message:
Epoch overflow!
Explanation
Each transaction needs to have a unique identifier. The epoch is an essential counter that ensures this uniqueness; if it
overflows then it will re-use old values and endanger transaction integrity. The transaction service will not allow this and
therefore throws this exception.
Suggestion
You are probably using an evaluation version of TransactionsJTA, which is limited in the number of times it can be used.
If you want to continue using TransactionsJTA, then you need to purchase a license.
During initialization of the transaction service, a runtime exception happens with message:
Log already in use?
Explanation
There should only be one running transaction manager that uses the physical log. Each transaction manager should have its
own log file, at the location specified in the configuration file. Either you have two services that use the same log file, or
the transaction service did not shutdown properly last time it was used.!
Suggestion
Assert that you have no two different servers that use the same log file. Check if no other instance of the server is running.
If the problem is due to improper shutdown, then manually delete the file with extension .lck in the log directory (after
you have made sure that the transaction service is no longer running). You can then restart the service.
One-phase commit/rollback takes a long time and finally an exception of type HeuristicMixedException is thrown.
Explanation
This happens if the transaction service can no longer contact the resource for commitment.
Suggestion
If you are doing XA-Level integration, then make sure that the XAConnection is closed only after the transaction has
committed or rolled back.
Commit often fails with a RollbackException, on repeated occasions and for transactions that access more than one
resource.
Explanation
This can happen if the transaction service can not contact one of the resources for two-phase commit.
Suggestion
If you are doing XA-Level integration, then make sure that the XAConnections are closed only after the transaction has
committed or rolled back.
During enlistResource or in a getConnection/send/receive operation an error happens with a message saying something like:
Already enlisted.
Explanation
TransactionsJTA does not allow the same XAResource to be enlisted twice in one transaction without a delistResource in
between. This error will also happen if you try to open two connections to the same DataSource without closing one first.
Suggestion
When enlisting a second XAResource to the same underlying system, serialize the enlistResource/delistResource
operations: do not enlist a second time before delisting the first XAResource. For a DataSource, always close a connection
before opening a second one.
Initialization fails after you have registered multiple resources in TSInitInfo, some of which are in weak compare mode.
Explanation
To preserve correctness of recovery, only one resource per vendor can be added in weak compare mode.
Suggestion
Do not include more than one resource of the same vendor in weak compare mode.
Unknown Resource
Problem Description
During enlistResource, send, receive or getConnection operations there is an exception with a message saying Unknown
resource.
Explanation
Suggestion
Make sure that the resource is included in the configuration. If so, then you might need to use the resource in weak
compare mode. See the JMS examples on how to do this.
Explanation
The VM does not exit because a Swing event thread is still running. This is normal behaviour.
Suggestion
Call System.exit() if you want a Swing application to exit. Since the Transaction Service's LocalLogAdministrator does
not know when your application needs to exit, it can not do this for you.
10. References
http://java.sun.com Sun's Java website with the JTA, JDBC and JMS specifications and extra information.
http://www.atomikos.com Atomikos' website; please check regularly for updates and support information.
Distributed Transaction Processing: The XA Specification (ISBN 1-872630-24-3).
Published by The Open Group (http://www.opengroup.org).