12.7. Use JTA Transactions
12.7.1. Transactions JTA Task Overview
The following procedures are useful when you need to use transactions in your application.
12.7.2. Control Transactions
This list of procedures outlines the different ways to control transactions in your applications which use JTA or JTS APIs.
12.7.3. Begin a Transaction
Get an instance of
UserTransaction
.You can get the instance using JNDI, injection, or an EJB's context, if the EJB uses bean-managed transactions, by means of a@TransactionManagement(TransactionManagementType.BEAN)
annotation.JNDI
new InitialContext().lookup("java:comp/UserTransaction")
Injection
@Resource UserTransaction userTransaction;
Context
- In a stateless/stateful bean:
@Resource SessionContext ctx; ctx.getUserTransaction();
- In a message-driven bean:
@Resource MessageDrivenContext ctx; ctx.getUserTransaction()
Call
UserTransaction
.begin()
after you connect to your datasource.... try { System.out.println("\nCreating connection to database: "+url); stmt = conn.createStatement(); // non-tx statement try { System.out.println("Starting top-level transaction."); userTransaction.begin(); stmtx = conn.createStatement(); // will be a tx-statement ... } }
One of the benefits of EJBs (either used with CMT or BMT) is that the container manages all the internals of the transactional processing, that is, you are free from taking care of transaction being part of XA transaction or transaction distribution amongst EAP containers.
The transaction begins. All uses of your datasource until you commit or roll back the transaction are transactional.
Note
12.7.4. Nested Transactions
12.7.5. Commit a Transaction
You must begin a transaction before you can commit it. For information on how to begin a transaction, refer to Section 12.7.3, “Begin a Transaction”.
Call the
commit()
method on theUserTransaction
.When you call thecommit()
method on theUserTransaction
, the Transaction Manager attempts to commit the transaction.@Inject private UserTransaction userTransaction; public void updateTable(String key, String value) EntityManager entityManager = entityManagerFactory.createEntityManager(); try { userTransaction.begin(): <!-- Perform some data manipulation using entityManager --> ... // Commit the transaction userTransaction.commit(); } catch (Exception ex) { <!-- Log message or notify Web page --> ... try { userTransaction.rollback(); } catch (SystemException se) { throw new RuntimeException(se); } throw new RuntimeException(e); } finally { entityManager.close(); } }
If you use Container Managed Transactions (CMT), you do not need to manually commit.
If you configure your bean to use Container Managed Transactions, the container will manage the transaction lifecycle for you based on annotations you configure in the code.@PersistenceContext private EntityManager em; @TransactionAttribute(TransactionAttributeType.REQUIRED) public void updateTable(String key, String value) <!-- Perform some data manipulation using entityManager --> ... }
Your datasource commits and your transaction ends, or an exception is thrown.
Note
12.7.6. Roll Back a Transaction
You must begin a transaction before you can roll it back. For information on how to begin a transaction, refer to Section 12.7.3, “Begin a Transaction”.
Call the
rollback()
method on theUserTransaction
.When you call therollback()
method on theUserTransaction
, the Transaction Manager attempts to roll back the transaction and return the data to its previous state.@Inject private UserTransaction userTransaction; public void updateTable(String key, String value) EntityManager entityManager = entityManagerFactory.createEntityManager(); try { userTransaction.begin(): <!-- Perform some data manipulation using entityManager --> ... // Commit the transaction userTransaction.commit(); } catch (Exception ex) { <!-- Log message or notify Web page --> ... try { userTransaction.rollback(); } catch (SystemException se) { throw new RuntimeException(se); } throw new RuntimeException(e); } finally { entityManager.close(); } }
If you use Container Managed Transactions (CMT), you do not need to manually roll back the transaction.
If you configure your bean to use Container Managed Transactions, the container will manage the transaction lifecycle for you based on annotations you configure in the code.Note
Rollback for CMT occurs if RuntimeException is thrown. You can also explicitly call thesetRollbackOnly
method to gain the rollback. Or, use the@ApplicationException(rollback=true
) for application exception to rollback.
Your transaction is rolled back by the Transaction Manager.
Note
12.7.7. Handle a Heuristic Outcome in a Transaction
Procedure 12.5. Handle a heuristic outcome in a transaction
Determine the cause
The over-arching cause of a heuristic outcome in a transaction is that a resource manager promised it could commit or roll-back, and then failed to fulfill the promise. This could be due to a problem with a third-party component, the integration layer between the third-party component and JBoss EAP 6, or JBoss EAP 6 itself.By far, the most common two causes of heuristic errors are transient failures in the environment and coding errors in the code dealing with resource managers.Fix transient failures in the environment
Typically, if there is a transient failure in your environment, you will know about it before you find out about the heuristic error. This could be a network outage, hardware failure, database failure, power outage, or a host of other things.If you experienced the heuristic outcome in a test environment, during stress testing, it provides information about weaknesses in your environment.Warning
JBoss EAP 6 will automatically recover transactions that were in a non-heuristic state at the time of the failure, but it does not attempt to recover heuristic transactions.Contact resource manager vendors
If you have no obvious failure in your environment, or the heuristic outcome is easily reproducible, it is probably a coding error. Contact third-party vendors to find out if a solution is available. If you suspect the problem is in the transaction manager of JBoss EAP 6 itself, contact Red Hat Global Support Services.In a test environment, delete the logs and restart JBoss EAP 6.
In a test environment, or if you do not care about the integrity of the data, deleting the transaction logs and restarting JBoss EAP 6 gets rid of the heuristic outcome. The transaction logs are located inEAP_HOME/standalone/data/tx-object-store/
for a standalone server, orEAP_HOME/domain/servers/SERVER_NAME/data/tx-object-store
in a managed domain, by default. In the case of a managed domain, SERVER_NAME refers to the name of the individual server participating in a server group.Note
The location of the transaction log also depends on the object store in use and the values set for theoject-store-relative-to
andobject-store-path
parameters. For file system logs (such as a standard shadow and HornetQ logs) the default direction location is used, but when using a JDBC object store, the transaction logs are stored in a database.Resolve the outcome by hand
The process of resolving the transaction outcome by hand is very dependent on the exact circumstance of the failure. Typically, you need to take the following steps, applying them to your situation:- Identify which resource managers were involved.
- Examine the state in the transaction manager and the resource managers.
- Manually force log cleanup and data reconciliation in one or more of the involved components.
The details of how to perform these steps are out of the scope of this documentation.
12.7.8. Transaction Timeouts
12.7.8.1. About Transaction Timeouts
12.7.8.2. Configure the Transaction Manager
default
, you may need to modify the steps and commands in the following ways.
Notes about the Example Commands
- For the Management Console, the
default
profile is the one which is selected when you first log into the console. If you need to modify the Transaction Manager's configuration in a different profile, select your profile instead ofdefault
, in each instruction.Similarly, substitute your profile for thedefault
profile in the example CLI commands. - If you use a Standalone Server, only one profile exists. Ignore any instructions to choose a specific profile. In CLI commands, remove the
/profile=default
portion of the sample commands.
Note
transactions
subsystem must be enabled. It is enabled by default, and required for many other subsystems to function properly, so it is very unlikely that it would be disabled.
To configure the TM using the web-based Management Console, select the Configuration tab from the top of the screen. If you use a managed domain, choose the correct profile from the Profile selection box at the top left. Expand the Container menu and select Transactions.
In the Management CLI, you can configure the TM using a series of commands. The commands all begin with /profile=default/subsystem=transactions/
for a managed domain with profile default
, or /subsystem=transactions
for a Standalone Server.
Important
Option | Description | CLI Command |
---|---|---|
Enable Statistics
|
Whether to enable transaction statistics. These statistics can be viewed in the Management Console in the Subsystem Metrics section of the Runtime tab.
| /profile=default/subsystem=transactions/:write-attribute(name=enable-statistics,value=true)
|
Enable TSM Status
|
Whether to enable the transaction status manager (TSM) service, which is used for out-of-process recovery. Running an out of process recovery manager to contact the ActionStatusService from different process is not supported (it is normally contacted in memory).
|
This configuration option is unsupported.
|
Default Timeout
|
The default transaction timeout. This defaults to
300 seconds. You can override this programmatically, on a per-transaction basis.
| /profile=default/subsystem=transactions/:write-attribute(name=default-timeout,value=300)
|
Object Store Path
|
A relative or absolute filesystem path where the TM object store stores data. By default relative to the
object-store-relative-to parameter's value.
| /profile=default/subsystem=transactions/:write-attribute(name=object-store-path,value=tx-object-store)
|
Object Store Path Relative To
|
References a global path configuration in the domain model. The default value is the data directory for JBoss EAP 6, which is the value of the property
jboss.server.data.dir , and defaults to EAP_HOME/domain/data/ for a Managed Domain, or EAP_HOME/standalone/data/ for a Standalone Server instance. The value of the object store object-store-path TM attribute is relative to this path.
| /profile=default/subsystem=transactions/:write-attribute(name=object-store-relative-to,value=jboss.server.data.dir)
|
Socket Binding
|
Specifies the name of the socket binding used by the Transaction Manager for recovery and generating transaction identifiers, when the socket-based mechanism is used. Refer to
process-id-socket-max-ports for more information on unique identifier generation. Socket bindings are specified per server group in the Server tab of the Management Console.
| /profile=default/subsystem=transactions/:write-attribute(name=socket-binding,value=txn-recovery-environment)
|
Status Socket Binding
|
Specifies the socket binding to use for the Transaction Status manager.
|
This configuration option is unsupported.
|
Recovery Listener
|
Whether or not the Transaction Recovery process should listen on a network socket. Defaults to
false .
| /profile=default/subsystem=transactions/:write-attribute(name=recovery-listener,value=false)
|
Option | Description | CLI Command |
---|---|---|
jts
|
Whether to use Java Transaction Service (JTS) transactions. Defaults to
false , which uses JTA transactions only.
| /profile=default/subsystem=transactions/:write-attribute(name=jts,value=false)
|
node-identifier
|
The node identifier for the Transaction Manager. This option is required in the following situations:
node-identifier must be unique for each Transaction Manager as it is required to enforce data integrity during recovery. The node-identifier must also be unique for JTA because multiple nodes may interact with the same resource manager or share a transaction object store.
| /profile=default/subsystem=transactions/:write-attribute(name=node-identifier,value=1)
|
process-id-socket-max-ports
|
The Transaction Manager creates a unique identifier for each transaction log. Two different mechanisms are provided for generating unique identifiers: a socket-based mechanism and a mechanism based on the process identifier of the process.
In the case of the socket-based identifier, a socket is opened and its port number is used for the identifier. If the port is already in use, the next port is probed, until a free one is found. The
process-id-socket-max-ports represents the maximum number of sockets the TM will try before failing. The default value is 10 .
| /profile=default/subsystem=transactions/:write-attribute(name=process-id-socket-max-ports,value=10)
|
process-id-uuid
|
Set to
true to use the process identifier to create a unique identifier for each transaction. Otherwise, the socket-based mechanism is used. Defaults to true . Refer to process-id-socket-max-ports for more information. To enable process-id-socket-binding , set process-id-uuid to false .
| /profile=default/subsystem=transactions/:write-attribute(name=process-id-uuid,value=true)
|
process-id-socket-binding
|
The name of the socket binding configuration to use if the transaction manager should use a socket-based process id. Will be
undefined if process-id-uuid is true ; otherwise must be set.
| /profile=default/subsystem=transactions/:write-attribute(name=process-id-socket-binding,value=true)
|
use-hornetq-store
|
Use HornetQ's journaled storage mechanisms instead of file-based storage, for the transaction logs. This is disabled by default, but can improve I/O performance. It is not recommended for JTS transactions on separate Transaction Managers. When changing this option, the server has to be restarted using the
shutdown command for the change to take effect.
| /profile=default/subsystem=transactions/:write-attribute(name=use-hornetq-store,value=false)
|
12.7.9. JTA Transaction Error Handling
12.7.9.1. Handle Transaction Errors
Note
This type of error often manifests itself when Hibernate is unable to obtain a database connection for lazy loading. If it happens frequently, you can lengthen the timeout value. Refer to Section 12.7.8.2, “Configure the Transaction Manager”.
NotSupportedException
exception
The NotSupportedException
exception usually indicates that you attempted to nest a JTA transaction, and this is not supported. If you were not attempting to nest a transaction, it is likely that another transaction was started in a thread pool task, but finished the task without suspending or ending the transaction.
UserTransaction
, which handles this automatically. If so, there may be a problem with a framework.
TransactionManager
or Transaction
methods directly, be aware of the following behavior when committing or rolling back a transaction. If your code uses TransactionManager
methods to control your transactions, committing or rolling back a transaction disassociates the transaction from the current thread. However, if your code uses Transaction
methods, the transaction may not be associated with the running thread, and you need to disassociate it from its threads manually, before returning it to the thread pool.
This error happens if you try to enlist a second non-XA resource into a transaction. If you need multiple resources in a transaction, they must be XA.