Red Hat Training

A Red Hat training course is available for Red Hat JBoss Enterprise Application Platform

12.7. Use JTA Transactions

12.7.2. Control Transactions

Introduction

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

This procedure shows how to begin a new transaction. The API is the same either you run Transaction Manager configured with JTA or JTS.
  1. 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()
  2. 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
            ...
        }
    }
    
Participate in an existing transaction using the JTS API.

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.

Result:

The transaction begins. All uses of your datasource until you commit or roll back the transaction are transactional.

Note

12.7.4. Nested Transactions

Nested transactions allow an application to create a transaction that is embedded in an existing transaction. In this model, multiple subtransactions can be embedded recursively in a transaction. Subtransactions can be committed or rolled back without committing or rolling back the parent transaction. However, the results of a commit operation are contingent upon the commitment of all the transaction's ancestors.
For implementation specific information, refer JBossTS JTS Development guide at https://docs.jboss.org/jbosstm/latest/guides/narayana-jts-development_guide.
Nested transactions are available only when used with the JTS API. Nested transaction are not a supported feature of EAP application server. In addition, many database vendors do not support nested transactions, so consult your database vendor before you add nested transactions to your application.

12.7.5. Commit a Transaction

This procedure shows how to commit a transaction using the Java Transaction API (JTA).
Prerequisites

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”.

  1. Call the commit() method on the UserTransaction.

    When you call the commit() method on the UserTransaction, 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();
        }
    }
    
  2. 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 -->
      ...
    }
    
Result

Your datasource commits and your transaction ends, or an exception is thrown.

Note

12.7.6. Roll Back a Transaction

This procedure shows how to roll back a transaction using the Java Transaction API (JTA).
Prerequisites

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”.

  1. Call the rollback() method on the UserTransaction.

    When you call the rollback() method on the UserTransaction, 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();
        }
    }
    
  2. 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 the setRollbackOnly method to gain the rollback. Or, use the @ApplicationException(rollback=true) for application exception to rollback.
Result

Your transaction is rolled back by the Transaction Manager.

Note

12.7.7. Handle a Heuristic Outcome in a Transaction

This procedure shows how to handle a heuristic outcome of a transaction using the Java Transaction API (JTA).
Heuristic transaction outcomes are uncommon and usually have exceptional causes. The word heuristic means "by hand", and that is the way that these outcomes usually have to be handled. Refer to Section 12.4.4, “About Heuristic Outcomes” for more information about heuristic transaction outcomes.

Procedure 12.5. Handle a heuristic outcome in a transaction

  1. 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.
  2. 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.
  3. 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.
  4. 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 in EAP_HOME/standalone/data/tx-object-store/ for a standalone server, or EAP_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 the oject-store-relative-to and object-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.
  5. 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:
    1. Identify which resource managers were involved.
    2. Examine the state in the transaction manager and the resource managers.
    3. 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

In order to preserve atomicity and adhere to the ACID standard for transactions, some parts of a transaction can be long-running. Transaction participants need to lock parts of datasources when they commit, and the transaction manager needs to wait to hear back from each transaction participant before it can direct them all whether to commit or roll back. Hardware or network failures can cause resources to be locked indefinitely.
Transaction timeouts can be associated with transactions in order to control their lifecycle. If a timeout threshold passes before the transaction commits or rolls back, the timeout causes the transaction to be rolled back automatically.
You can configure default timeout values for the entire transaction subsystem, or you disable default timeout values, and specify timeouts on a per-transaction basis.

12.7.8.2. Configure the Transaction Manager

You can configure the Transaction Manager (TM) using the web-based Management Console or the command-line Management CLI. For each command or option given, the assumption is made that you are running JBoss EAP 6 as a Managed Domain. If you use a Standalone Server or you want to modify a different profile than 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 of default, in each instruction.
    Similarly, substitute your profile for the default 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

In order for the TM options to be visible in the Management Console or Management CLI, the 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.
Configure the TM Using the Management Console

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.

Most options are shown in the Transaction Manager configuration page. The Recovery options are hidden by default. Click the Recovery tab to see the recovery options. Click Edit to edit any of the options. Changes take effect immediately.
Click the Need Help? label to display in-line help text.
Configure the TM using the Management CLI

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

If transaction subsystem is configured to use hornetq journal as storage type for transaction logs, then two instances of JBoss EAP is not permitted to use the same directory for storing the journal. Application server instances can't share the same location and each has to configure unique location for it.

Table 12.13. TM Configuration Options

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)
The following options are for advanced use and can only be modified using the Management CLI. Be cautious when changing them from the default configuration. Contact Red Hat Global Support Services for more information.

Table 12.14. Advanced TM Configuration Options

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:
  • For JTS to JTS communications
  • When two Transaction Managers access shared resource managers
  • When two Transaction Managers access shared object stores
The 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

Transaction errors are challenging to solve because they are often dependent on timing. Here are some common errors and ideas for troubleshooting them.

Note

These guidelines do not apply to heuristic errors. If you experience heuristic errors, refer to Section 12.7.7, “Handle a Heuristic Outcome in a Transaction” and contact Red Hat Global Support Services for assistance.
The transaction timed out but the business logic thread did not notice

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”.

If that is not feasible, you may be able to tune your external environment to perform more quickly, or restructure your code to be more efficient. Contact Red Hat Global Support Services if you still have trouble with timeouts.
The transaction is already running on a thread, or you receive a 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.

Applications typically use UserTransaction, which handles this automatically. If so, there may be a problem with a framework.
If your code does use 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.
You are unable to enlist a second local resource

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.