Search

Chapter 11. Java Transaction API (JTA)

download PDF

11.1. Overview

11.1.1. Overview of Java Transaction API (JTA)

Introduction

This section provides a foundational understanding of the Java Transaction API (JTA).

11.2. Transaction Concepts

11.2.1. About Transactions

A transaction consists of two or more actions, which must either all succeed or all fail. A successful outcome is a commit, and a failed outcome is a rollback. In a rollback, each member’s state is reverted to its state before the transaction attempted to commit.

The typical standard for a well-designed transaction is that it is Atomic, Consistent, Isolated, and Durable (ACID).

11.2.2. About ACID Properties for Transactions

ACID is an acronym which stands for Atomicity, Consistency, Isolation, and Durability. This terminology is usually used in the context of databases or transactional operations.

Atomicity
For a transaction to be atomic, all transaction members must make the same decision. Either they all commit, or they all roll back. If atomicity is broken, what results is termed a heuristic outcome.
Consistency
Consistency means that data written to the database is guaranteed to be valid data, in terms of the database schema. The database or other data source must always be in a consistent state. One example of an inconsistent state would be a field in which half of the data is written before an operation aborts. A consistent state would be if all the data were written, or the write were rolled back when it could not be completed.
Isolation
Isolation means that data being operated on by a transaction must be locked before modification, to prevent processes outside the scope of the transaction from modifying the data.
Durability
Durability means that in the event of an external failure after transaction members have been instructed to commit, all members will be able to continue committing the transaction when the failure is resolved. This failure can be related to hardware, software, network, or any other involved system.

11.2.3. About the Transaction Coordinator or Transaction Manager

The terms Transaction Coordinator and Transaction Manager (TM) are mostly interchangeable in terms of transactions with JBoss EAP. The term Transaction Coordinator is usually used in the context of distributed JTS transactions.

In JTA transactions, the TM runs within JBoss EAP and communicates with transaction participants during the two-phase commit protocol.

The TM tells transaction participants whether to commit or roll back their data, depending on the outcome of other transaction participants. In this way, it ensures that transactions adhere to the ACID standard.

11.2.4. About Transaction Participants

A transaction participant is any resource within a transaction that has the ability to commit or to roll back state. It is generally a database or a JMS broker, but by implementing the transaction interface, application code could also act as a transaction participant. Each participant of a transaction independently decides whether it is able to commit or roll back its state, and only if all participants can commit does the transaction as a whole succeed. Otherwise, each participant rolls back its state, and the transaction as a whole fails. The TM coordinates the commit or rollback operations and determines the outcome of the transaction.

11.2.5. About Java Transaction API (JTA)

Java Transaction API (JTA) is part of Java Enterprise Edition specification. It is defined in JSR 907: Java™ Transaction API (JTA).

Implementation of JTA is done using the TM, which is covered by project Narayana for JBoss EAP application server. The TM allows applications to assign various resources, for example, database or JMS brokers, through a single global transaction. The global transaction is referred as an XA transaction. Generally resources with XA capabilities are included in such transactions, but non-XA resources could also be part of global transactions. There are several optimizations which help non-XA resources to behave as XA capable resources. For more information, see LRCO Optimization for Single-phase Commit.

In this document, the term JTA refers to two things:

  1. The Java Transaction API, which is defined by Java EE specification.
  2. It indicates how the TM processes the transactions.

The TM works in JTA transactions mode, the data is shared in memory, and the transaction context is transferred by remote EJB calls. In JTS mode, the data is shared by sending Common Object Request Broker Architecture (CORBA) messages and the transaction context is transferred by IIOP calls. Both modes support distribution of transactions over multiple JBoss EAP servers.

11.2.6. About Java Transaction Service (JTS)

Java Transaction Service (JTS) is a mapping of the Object Transaction Service (OTS) to Java. Java EE applications use the JTA API to manage transactions. JTA API then interacts with a JTS transaction implementation when the transaction manager is switched to JTS mode. JTS works over the IIOP protocol. Transaction managers that use JTS communicate with each other using a process called an Object Request Broker (ORB), using a communication standard called Common Object Request Broker Architecture (CORBA). For more information, see ORB Configuration in the JBoss EAP Configuration Guide.

Using the JTA API from an application standpoint, a JTS transaction behaves in the same way as a JTA transaction.

Note

The implementation of JTS included in JBoss EAP supports distributed transactions. The difference from fully-compliant JTS transactions is interoperability with external third-party ORBs. This feature is unsupported with JBoss EAP. Supported configurations distribute transactions across multiple JBoss EAP containers only.

11.2.7. About XML Transaction Service

The XML Transaction Service (XTS) component supports the coordination of private and public web services in a business transaction. Using XTS, you can coordinate complex business transactions in a controlled and reliable manner. The XTS API supports a transactional coordination model based on the WS-Coordination, WS-Atomic Transaction, and WS-Business Activity protocols.

11.2.7.1. Overview of Protocols Used by XTS

The WS-Coordination (WS-C) specification defines a framework that allows different coordination protocols to be plugged in to coordinate work between clients, services, and participants.

The WS-Transaction (WS-T) protocol comprises the pair of transaction coordination protocols, WS-Atomic Transaction (WS-AT) and WS-Business Activity (WS-BA), which utilize the coordination framework provided by WS-C. WS-T is developed to unify existing traditional transaction processing systems, allowing them to communicate reliably with one another.

11.2.7.2. Web Services-Atomic Transaction Process

An atomic transaction (AT) is designed to support short duration interactions where ACID semantics are appropriate. Within the scope of an AT, web services typically employ bridging to access XA resources, such as databases and message queues, under the control of the WS-T. When the transaction terminates, the participant propagates the outcome decision of the AT to the XA resources, and the appropriate commit or rollback actions are taken by each participant.

11.2.7.2.1. Atomic Transaction Process
  1. To initiate an AT, the client application first locates a WS-C Activation Coordinator web service that supports WS-T.
  2. The client sends a WS-C CreateCoordinationContext message to the service, specifying http://schemas.xmlsoap.org/ws/2004/10/wsat as its coordination type.
  3. The client receives an appropriate WS-T context from the activation service.
  4. The response to the CreateCoordinationContext message, the transaction context, has its CoordinationType element set to the WS-AT namespace, http://schemas.xmlsoap.org/ws/2004/10/wsat. It also contains a reference to the atomic transaction coordinator endpoint, the WS-C Registration Service, where participants can be enlisted.
  5. The client normally proceeds to invoke web services and complete the transaction, either committing all the changes made by the web services, or rolling them back. In order to be able to drive this completion, the client must register itself as a participant for the completion protocol, by sending a register message to the registration service whose endpoint was returned in the coordination context.
  6. Once registered for completion, the client application then interacts with web services to accomplish its business-level work. With each invocation of a business web service, the client inserts the transaction context into a SOAP header block, such that each invocation is implicitly scoped by the transaction. The toolkits that support WS-AT aware web services provide facilities to correlate contexts found in SOAP header blocks with back-end operations. This ensures that modifications made by the web service are done within the scope of the same transaction as the client and subject to commit or rollback by the Transaction Coordinator.
  7. Once all the necessary application work is complete, the client can terminate the transaction, with the intent of making any changes to the service state permanent. The completion participant instructs the coordinator to try to commit or roll back the transaction. When the commit or rollback operation completes, a status is returned to the participant to indicate the outcome of the transaction.

For more details, see WS-Coordination in the Naryana Project Documentation.

11.2.7.3. Web Services-Business Activity Process

Web Services-Business Activity (WS-BA) defines a protocol for web service applications to enable existing business processing and workflow systems to wrap their proprietary mechanisms and interoperate across implementations and business boundaries.

Unlike the WS-AT protocol model, where participants inform the transaction coordinator of their state only when asked, a child activity within a WS-BA can specify its outcome to the coordinator directly, without waiting for a request. A participant can choose to exit the activity or notify the coordinator of a failure at any point. This feature is useful when tasks fail because the notification can be used to modify the goals and drive processing forward, without waiting until the end of the transaction to identify failures.

11.2.7.3.1. WS-BA Process
  1. Services are requested to do work.
  2. Wherever these services have the ability to undo any work, they inform the WS-BA, in case the WS-BA later decides the cancel the work. If the WS-BA suffers a failure. it can instruct the service to execute its undo behavior.

The WS-BA protocols employ a compensation-based transaction model. When a participant in a business activity completes its work, it can choose to exit the activity. This choice does not allow any subsequent rollback. Alternatively, the participant can complete its activity, signaling to the coordinator that the work it has done can be compensated if, at some later point, another participant notifies a failure to the coordinator. In this latter case, the coordinator asks each non-exited participant to compensate for the failure, giving them the opportunity to execute whatever compensating action they consider appropriate. If all participants exit or complete without failure, the coordinator notifies each completed participant that the activity has been closed.

For more details, see WS-Coordination in the Naryana Project Documentation.

11.2.7.4. Transaction Bridging Overview

Transaction Bridging describes the process of linking the Java EE and WS-T domains. The transaction bridge component, txbridge, provides bi-directional linkage, such that either type of transaction can encompass business logic designed for use with the other type. The technique used by the bridge is a combination of interposition and protocol mapping.

In the transaction bridge, an interposed coordinator is registered into the existing transaction and performs the additional task of protocol mapping; that is, it appears to its parent coordinator to be a resource of its native transaction type, while appearing to its children to be a coordinator of their native transaction type, even though these transaction types differ.

The transaction bridge resides in the package org.jboss.jbossts.txbridge and its subpackages. It consists of two distinct sets of classes, one for bridging in each direction.

For more details, see TXBridge Guide in the Naryana Project Documentation.

11.2.8. About XA Resources and XA Transactions

XA stands for eXtended Architecture, which was developed by the X/Open Group to define a transaction that uses more than one back-end data store. The XA standard describes the interface between a global TM and a local resource manager. XA allows multiple resources, such as application servers, databases, caches, and message queues, to participate in the same transaction, while preserving all four ACID properties. One of the four ACID properties is atomicity, which means that if one of the participants fails to commit its changes, the other participants abort the transaction, and restore their state to the same status as before the transaction occurred. An XA resource is a resource that can participate in an XA global transaction.

An XA transaction is a transaction that can span multiple resources. It involves a coordinating TM, with one or more databases or other transactional resources, all involved in a single global XA transaction.

11.2.9. About XA Recovery

TM implements X/Open XA specification and supports XA transactions across multiple XA resources.

XA Recovery is the process of ensuring that all resources affected by a transaction are updated or rolled back, even if any of the resources that are transaction participants crash or become unavailable. Within the scope of JBoss EAP, the transactions subsystem provides the mechanisms for XA Recovery to any XA resources or subsystems that use them, such as XA datasources, JMS message queues, and JCA resource adapters.

XA Recovery happens without user intervention. In the event of an XA Recovery failure, errors are recorded in the log output. Contact Red Hat Global Support Services if you need assistance. The XA recovery process is driven by a periodic recovery thread which is launched by default every two minutes. The periodic recovery thread processes all unfinished transactions.

Note

It can take four to eight minutes to complete the recovery for an in-doubt transaction because it might require multiple runs of the recovery process.

11.2.10. Limitations of the XA Recovery Process

XA recovery has the following limitations:

  • The transaction log might not be cleared from a successfully committed transaction.

    If the JBoss EAP server crashes after an XAResource commit method successfully completes and commits the transaction, but before the coordinator can update the log, you might see the following warning message in the log when you restart the server:

    ARJUNA016037: Could not find new XAResource to use for recovering non-serializable XAResource XAResourceRecord

    This is because upon recovery, the JBoss Transaction Manager (TM) sees the transaction participants in the log and attempts to retry the commit. Eventually the JBoss TM assumes the resources are committed and no longer retries the commit. In this situation, you can safely ignore this warning as the transaction is committed and there is no loss of data.

    To prevent the warning, set the com.arjuna.ats.jta.xaAssumeRecoveryComplete property value to true . This property is checked whenever a new XAResource instance cannot be located from any registered XAResourceRecovery instance. When set to true, the recovery assumes that a previous commit attempt succeeded and the instance can be removed from the log with no further recovery attempts. This property must be used with care because it is global and when used incorrectly could result in XAResource instances remaining in an uncommitted state.

    Note

    JBoss EAP 7.1 has an implemented enhancement to clear transaction logs after a successfully committed transaction and the above situation should not occur frequently.

  • Rollback is not called for JTS transaction when a server crashes at the end of XAResource.prepare().

    If the JBoss EAP server crashes after the completion of an XAResource.prepare() method call, all of the participating XAResource instances are locked in the prepared state and remain that way upon server restart. The transaction is not rolled back and the resources remain locked until the transaction times out or a database administrator manually rolls back the resources and clears the transaction log. For more information, see https://issues.jboss.org/browse/JBTM-2124

  • Periodic recovery can occur on committed transactions.

    When the server is under excessive load, the server log might contain the following warning message, followed by a stacktrace:

    ARJUNA016027: Local XARecoveryModule.xaRecovery got XA exception XAException.XAER_NOTA: javax.transaction.xa.XAException

    Under heavy load, the processing time taken by a transaction can overlap with the timing of the periodic recovery process’s activity. The periodic recovery process detects the transaction still in progress and attempts to initiate a rollback but in fact the transaction continues to completion. At the time the periodic recovery attempts but fails the rollback, it records the rollback failure in the server log. The underlying cause of this issue will be addressed in a future release, but in the meantime a workaround is available.

    Increase the interval between the two phases of the recovery process by setting the com.arjuna.ats.jta.orphanSafetyInterval property to a value higher than the default value of 10000 milliseconds. A value of 40000 milliseconds is recommended. Note that this does not solve the issue. Instead it decreases the probability that it will occur and that the warning message will be shown in the log. For more information, see https://developer.jboss.org/thread/266729

11.2.11. About the 2-Phase Commit Protocol

The two-phase commit (2PC) protocol refers to an algorithm to determine the outcome of a transaction. 2PC is driven by the Transaction Manager (TM) as a process of finishing XA transactions.

Phase 1: Prepare

In the first phase, the transaction participants notify the transaction coordinator whether they are able to commit the transaction or must roll back.

Phase 2: Commit

In the second phase, the transaction coordinator makes the decision about whether the overall transaction should commit or roll back. If any one of the participants cannot commit, the transaction must roll back. Otherwise, the transaction can commit. The coordinator directs the resources about what to do, and they notify the coordinator when they have done it. At that point, the transaction is finished.

11.2.12. 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 an XA resource that is part of database table or message in a queue when they commit. The TM 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 can disable default timeout values and specify timeouts on a per-transaction basis.

11.2.13. About Distributed Transactions

A distributed transaction is a transaction with participants on multiple JBoss EAP servers. The Java Transaction Service (JTS) specification mandates that JTS transactions be able to be distributed across application servers from different vendors. The Java Transaction API (JTA) does not define that but JBoss EAP supports distributed JTA transactions among JBoss EAP servers.

Note

Transaction distribution among servers from different vendors is not supported.

Note

In other application server vendor documentation, you might find that the term distributed transaction means XA transaction. In the context of JBoss EAP documentation, the distributed transaction refers to transactions distributed among several JBoss EAP application servers. Transactions that consist of different resources, for example, database resources and JMS resources, are referred as XA transactions in this document. For more information, see About Java Transaction Service (JTS) and About XA Datasources and XA Transactions.

11.2.14. About the ORB Portability API

The Object Request Broker (ORB) is a process that sends and receives messages to transaction participants, coordinators, resources, and other services distributed across multiple application servers. An ORB uses a standardized Interface Description Language (IDL) to communicate and interpret messages. Common Object Request Broker Architecture (CORBA) is the IDL used by the ORB in JBoss EAP.

The main type of service that uses an ORB is a system of distributed Java Transactions, using the Java Transaction Service (JTS) specification. Other systems, especially legacy systems, can choose to use an ORB for communication rather than other mechanisms such as remote Enterprise JavaBeans or JAX-WS or JAX-RS web services.

The ORB Portability API provides mechanisms to interact with an ORB. This API provides methods for obtaining a reference to the ORB, as well as placing an application into a mode where it listens for incoming connections from an ORB. Some of the methods in the API are not supported by all ORBs. In those cases, an exception is thrown.

The API consists of two different classes:

  • com.arjuna.orbportability.orb
  • com.arjuna.orbportability.oa

See the JBoss EAP Javadocs bundle available on the Red Hat Customer Portal for specific details about the methods and properties included in the ORB Portability API.

11.3. Transaction Optimizations

11.3.1. Overview of Transaction Optimizations

The Transaction Manager (TM) of JBoss EAP includes several optimizations that your application can take advantage of.

Optimizations serve to enhance the 2-phase commit protocol in particular cases. Generally, the TM starts a global transaction, which passes through the 2-phase commit. But when you optimize these transactions, in certain cases, the TM does not need to proceed with full 2-phased commits and thus the process gets faster.

Different optimizations used by the TM are described in detail below.

11.3.2. About the LRCO Optimization for Single-phase Commit (1PC)

Single-phase Commit (1PC)

Although the 2-phase commit protocol (2PC) is more commonly encountered with transactions, some situations do not require, or cannot accommodate, both phases. In these cases, you can use the single phase commit (1PC) protocol. The single phase commnit protocol is used when only one XA or non-XA resource is a part of the global transaction.

The prepare phase generally locks the resource until the second phase is processed. Single-phase commit means that the prepare phase is skipped and only the commit is processed on the resource. If not specified, the single-phase commit optimization is used automatically when the global transaction contains only one participant.

Last Resource Commit Optimization (LRCO)

In situations where non-XA datasource participate in XA transaction, an optimization known as the Last Resource Commit Optimization (LRCO) is employed. While this protocol allows for most transactions to complete normally, certain types of error can cause an inconsistent transaction outcome. Therefore, use this approach only as a last resort.

The non-XA resource is processed at the end of the prepare phase, and an attempt is made to commit it. If the commit succeeds, the transaction log is written and the remaining resources go through the commit phase. If the last resource fails to commit, the transaction is rolled back.

Where a single local TX datasource is used in a transaction, the LRCO is automatically applied to it.

Previously, adding non-XA resources to an XA transaction was achieved via the LRCO method. However, there is a window of failure in LRCO. The procedure for adding non-XA resources to an XA transaction using the LRCO method is as follows:

  1. Prepare the XA transaction.
  2. Commit LRCO.
  3. Write the transaction log.
  4. Commit the XA transaction.

If the procedure crashes between step 2 and step 3, this could lead to data inconsistency and you cannot commit the XA transaction. The data inconsistency is because the LRCO non-XA resource is committed but information about preparation of XA resource was not recorded. The recovery manager will rollback the resource after the server is up. Commit Markable Resource (CMR) eliminates this restriction and allows a non-XA resource to be reliably enlisted in an XA transaction.

Note

CMR is a special case of LRCO optimization that should only be used for datasources. It is not suitable for all non-XA resources.

11.3.2.1. Commit Markable Resource

Summary

Configuring access to a resource manager using the Commit Markable Resource (CMR) interface ensures that a non-XA datasource can be reliably enlisted in an XA (2PC) transaction. It is an implementation of the LRCO algorithm, which makes non-XA resource fully recoverable.

To configure the CMR, you must:

  1. Create tables in a database.
  2. Enable the datasource to be connectable.
  3. Add a reference to transactions subsystem.
Create Tables in Database

A transaction can contain only one CMR resource. You can create a table using SQL similar to the following example.

SELECT xid,actionuid FROM _tableName_ WHERE transactionManagerID IN (String[])
DELETE FROM _tableName_ WHERE xid IN (byte[[]])
INSERT INTO _tableName_ (xid, transactionManagerID, actionuid) VALUES (byte[],String,byte[])

The following are examples of the SQL syntax to create tables for various database management systems.

Example: Sybase Create Table Syntax

CREATE TABLE xids (xid varbinary(144), transactionManagerID varchar(64), actionuid varbinary(28))

Example: Oracle Create Table Syntax

CREATE TABLE xids (xid RAW(144), transactionManagerID varchar(64), actionuid RAW(28))
CREATE UNIQUE INDEX index_xid ON xids (xid)

Example: IBM Create Table Syntax

CREATE TABLE xids (xid VARCHAR(255) for bit data not null, transactionManagerID
varchar(64), actionuid VARCHAR(255) for bit data not null)
CREATE UNIQUE INDEX index_xid ON xids (xid)

Example: SQL Server Create Table Syntax

CREATE TABLE xids (xid varbinary(144), transactionManagerID varchar(64), actionuid varbinary(28))
CREATE UNIQUE INDEX index_xid ON xids (xid)

Example: PostgreSQL Create Table Syntax

CREATE TABLE xids (xid bytea, transactionManagerID varchar(64), actionuid bytea)
CREATE UNIQUE INDEX index_xid ON xids (xid)

Example: MariaDB Create Table Syntax

CREATE TABLE xids (xid BINARY(144), transactionManagerID varchar(64), actionuid BINARY(28))
CREATE UNIQUE INDEX index_xid ON xids (xid)

Example: MySQL Create Table Syntax

CREATE TABLE xids (xid VARCHAR(255), transactionManagerID varchar(64), actionuid VARCHAR(255))
CREATE UNIQUE INDEX index_xid ON xids (xid)

Enabling Datasource to be Connectable

By default, the CMR feature is disabled for datasources. To enable it, you must create or modify the datasource configuration and ensure that the connectable attribute is set to true. The following is an example of the datasources section of a server XML configuration file:

<datasource enabled="true" jndi-name="java:jboss/datasources/ConnectableDS" pool-name="ConnectableDS" jta="true" use-java-context="true" connectable="true"/>
Note

This feature is not applicable to XA datasources.

You can also enable a resource manager as a CMR, using the management CLI, as follows:

/subsystem=datasources/data-source=ConnectableDS:add(enabled="true", jndi-name="java:jboss/datasources/ConnectableDS", jta="true", use-java-context="true", connectable="true", connection-url="validConnectionURL", exception-sorter-class-name="org.jboss.jca.adapters.jdbc.extensions.mssql.MSSQLExceptionSorter", driver-name="mssql")

This command generates the following XML in the datasources section of the server configuration file.

<datasource jta="true" jndi-name="java:jboss/datasources/ConnectableDS" pool-name="ConnectableDS" enabled="true" use-java-context="true" connectable="true">
  <connection-url>validConnectionURL</connection-url>
  <driver>mssql</driver>
  <validation>
    <exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.mssql.MSSQLExceptionSorter"/>
  </validation>
</datasource>
Note

The datasource must have a valid driver defined. The example above uses mssql as the driver-name; however the mssql driver does not exist. For details, see Example MySQL Datasource in the JBoss EAP Configuration Guide.

Note

Use the exception-sorter-class-name parameter in the datasource configuration. For details, see Example Datasource Configurations in the JBoss EAP Configuration Guide.

Updating an Existing Resource to Use the New CMR Feature

If you only need to update an existing datasource to use the CMR feature, then simply modify the connectable attribute:

/subsystem=datasources/data-source=ConnectableDS:write-attribute(name=connectable,value=true)
Add a Reference to the Transactions Subsystem

The transactions subsystem identifies the datasources that are CMR capable through an entry to the transactions subsystem configuration section as shown below:

<subsystem xmlns="urn:jboss:domain:transactions:3.0">
    ...
    <commit-markable-resources>
        <commit-markable-resource jndi-name="java:jboss/datasources/ConnectableDS">
            <xid-location name="xids" batch-size="100" immediate-cleanup="false"/>
        </commit-markable-resource>
        ...
    </commit-markable-resources>
</subsystem>

The same result can be achieved using the management CLI:

/subsystem=transactions/commit-markable-resource=java\:jboss\/datasources\/ConnectableDS/:add(batch-size=100,immediate-cleanup=false,name=xids)
Note

You must restart the server after adding the CMR reference under the transactions subsystem.

11.3.3. About the Presumed-Abort Optimization

If a transaction is going to roll back, it can record this information locally and notify all enlisted participants. This notification is only a courtesy, and has no effect on the transaction outcome. After all participants have been contacted, the information about the transaction can be removed.

If a subsequent request for the status of the transaction occurs there will be no information available. In this case, the requester assumes that the transaction has aborted and rolled back. This presumed-abort optimization means that no information about participants needs to be made persistent until the transaction has decided to commit, since any failure prior to this point will be assumed to be an abort of the transaction.

11.3.4. About the Read-Only Optimization

When a participant is asked to prepare, it can indicate to the coordinator that it has not modified any data during the transaction. Such a participant does not need to be informed about the outcome of the transaction, since the fate of the participant has no affect on the transaction. This read-only participant can be omitted from the second phase of the commit protocol.

11.4. Transaction Outcomes

11.4.1. About Transaction Outcomes

There are three possible outcomes for a transaction.

Commit
If every transaction participant can commit, the transaction coordinator directs them to do so. See About Transaction Commit for more information.
Rollback
If any transaction participant cannot commit, or if the transaction coordinator cannot direct participants to commit, the transaction is rolled back. See About Transaction Rollback for more information.
Heuristic outcome
If some transaction participants commit and others roll back, it is termed a heuristic outcome. Heuristic outcomes require human intervention. See About Heuristic Outcomes for more information.

11.4.2. About Transaction Commit

When a transaction participant commits, it makes its new state durable. The new state is created by the participant doing the work involved in the transaction. The most common example is when a transaction member writes records to a database.

After a commit, information about the transaction is removed from the transaction coordinator, and the newly-written state is now the durable state.

11.4.3. About Transaction Rollback

A transaction participant rolls back by restoring its state to reflect the state before the transaction began. After a rollback, the state is the same as if the transaction had never been started.

11.4.4. About Heuristic Outcomes

A heuristic outcome, or non-atomic outcome, is a situation where the decisions of the participants in a transaction differ from that of the transaction manager. Heuristic outcomes can cause loss of integrity to the system, and usually require human intervention to resolve them. Do not write code which relies on them.

Heuristic outcomes typically occur during the second phase of the 2-phase commit (2PC) protocol. In rare cases, this outcome might occur in a 1PC. They are often caused by failures to the underlying hardware or communications subsystems of the underlying servers.

Heuristic outcomes are possible due to timeouts in various subsystems or resources even with transaction manager and full crash recovery. In any system that requires some form of distributed agreement, situations can arise where some parts of the system diverge in terms of the global outcome.

There are four different types of heuristic outcomes:

Heuristic rollback

The commit operation was not able to commit the resources but all of the participants were able to be rolled back and so an atomic outcome was still achieved.

Heuristic commit

An attempted rollback operation failed because all of the participants unilaterally committed. This can happen if, for example, the coordinator is able to successfully prepare the transaction but then decides to roll it back because of a failure on its side, such as a failure to update its log. In the interim, the participants might decide to commit.

Heuristic mixed

Some participants committed and others rolled back.

Heuristic hazard

The disposition of some of the updates is unknown. For those that are known, they have either all been committed or all rolled back.

11.4.5. JBoss Transactions Errors and Exceptions

For details about exceptions thrown by methods of the UserTransaction class, see the UserTransaction API Javadoc.

11.5. Overview of the Transaction Lifecycle

11.5.1. Transaction Lifecycle

See About Java Transaction API (JTA) for more information on Java Transaction API (JTA).

When a resource asks to participate in a transaction, a chain of events is set in motion. The Transaction Manager (TM) is a process that lives within the application server and manages transactions. Transaction participants are objects which participate in a transaction. Resources are datasources, JMS connection factories, or other JCA connections.

  1. The application starts a new transaction.

    To begin a transaction, the application obtains an instance of class UserTransaction from JNDI or, if it is an EJB, from an annotation. The UserTransaction interface includes methods for beginning, committing, and rolling back top-level transactions. Newly created transactions are automatically associated with their invoking thread. Nested transactions are not supported in JTA, so all transactions are top-level transactions.

    An EJB starts a transaction when the UserTransaction.begin() method is called. The default behavior of this transaction could be affected by use of the TransactionAttribute annotation or the ejb.xml descriptor. Any resource that is used after that point is associated with the transaction. If more than one resource is enlisted, the transaction becomes an XA transaction, and participates in the two-phase commit protocol at commit time.

    Note

    By default, transactions are driven by application containers in EJBs. This is called Container Managed Transaction (CMT). To make the transaction user driven, change the Transaction Management to Bean Managed Transaction (BMT). In BMT, the UserTransaction object is available for the user to manage the transaction.

  2. The application modifies its state.

    In the next step, the application performs its work and makes changes to its state, only on enlisted resources.

  3. The application decides to commit or roll back.

    When the application has finished changing its state, it decides whether to commit or roll back. It calls the appropriate method, either UserTransaction.commit() or UserTransaction.rollback(). For a CMT, this process is driven automatically, whereas for a BMT, a method commit or rollback of the UserTransaction has to be explicitly called.

  4. The TM removes the transaction from its records.

    After the commit or rollback completes, the TM cleans up its records and removes information about the transaction from the transaction log.

Failure Recovery

If a resource, transaction participant, or the application server crashes or become unavailable, the Transaction Manager handles recovery when the underlying failure is resolved and the resource is available again. This process happens automatically. For more information, see XA Recovery.

11.6. Transaction Subsystem Configuration

The transactions subsystem allows you to configure transaction manager options such as statistics, timeout values, and transaction logging. You can also manage transactions and view transaction statistics.

For more information, see Configuring Transactions in the JBoss EAP Configuration Guide.

11.7. Transactions Usage In Practice

11.7.1. Transactions Usage Overview

The following procedures are useful when you need to use transactions in your application.

11.7.2. Control Transactions

Introduction

This list of procedures outlines the different ways to control transactions in your applications which use JTA APIs.

11.7.2.1. Begin a Transaction

This procedure shows how to begin a new transaction. The API is the same whether you run the Transaction Manager (TM) 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.

    • Get the instance using JNDI.

      new InitialContext().lookup("java:comp/UserTransaction")
    • Get the instance using injection.

      @Resource UserTransaction userTransaction;
    • Get the instance using the EJB 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
            ...
        }
    }

Result

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

For a full example, see JTA Transaction Example.

Note

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 JBoss EAP containers.

11.7.2.1.1. 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, see the Narayana Project Documentation.

Nested transactions are available only when used with the JTS specification. Nested transactions are not a supported feature of JBoss 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.

11.7.2.2. 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, see Begin a Transaction.

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

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

For a full example, see JTA Transaction Example.

11.7.2.3. 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, see Begin a Transaction.

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

    When you call the rollback() method on the UserTransaction, the TM 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 TM.

Note

For a full example, see JTA Transaction Example.

11.7.3. Handle a Heuristic Outcome in a Transaction

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. See About Heuristic Outcomes for more information about heuristic transaction outcomes.

This procedure shows how to handle a heuristic outcome of a transaction using the Java Transaction API (JTA).

  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 rollback, 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, or JBoss EAP itself.

    By far, the most common two causes of heuristic errors are transient failures in the environment and coding errors 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 experience a heuristic outcome in a test environment during stress testing, it provides information about weaknesses in your environment.

    Warning

    JBoss EAP automatically recovers 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 if the heuristic outcome is easily reproducible, it is probably due to a coding error. Contact third-party vendors to find out if a solution is available. If you suspect the problem is in the TM of JBoss EAP itself, contact Red Hat Global Support Services.
  4. Try to manually recover a transaction through the management CLI. For more information, see the Recover a Transaction Participant section of the JBoss EAP Configuration Guide.
  5. In a test environment, delete the logs and restart JBoss EAP: In a test environment, or if you do not care about the integrity of the data, deleting the transaction logs and restarting JBoss EAP gets rid of the heuristic outcome. By default, the transaction logs are located in the EAP_HOME/standalone/data/tx-object-store/ directory for a standalone server, or the EAP_HOME/domain/servers/SERVER_NAME/data/tx-object-store/ directory in a managed domain. 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 object-store-relative-to and object-store-path parameters. For file system logs, such as a standard shadow and Apache ActiveMQ Artemis logs, the default directory location is used, but when using a JDBC object store, the transaction logs are stored in a database.

  6. 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 TM 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.

11.7.4. JTA Transaction Error Handling

11.7.4.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 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. See the JBoss EAP Configuration Guide for information on configuring the transaction manager.

If that is not feasible, you might 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 might 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 might 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.

11.8. Transaction References

11.8.1. JTA Transaction Example

This example illustrates how to begin, commit, and roll back a JTA transaction. You need to adjust the connection and datasource parameters to suit your environment, and set up two test tables in your database.

public class JDBCExample {
    public static void main (String[] args) {
        Context ctx = new InitialContext();
        // Change these two lines to suit your environment.
        DataSource ds = (DataSource)ctx.lookup("jdbc/ExampleDS");
        Connection conn = ds.getConnection("testuser", "testpwd");
        Statement stmt = null; // Non-transactional statement
        Statement stmtx = null; // Transactional statement
        Properties dbProperties = new Properties();

        // Get a UserTransaction
        UserTransaction txn = new InitialContext().lookup("java:comp/UserTransaction");

        try {
            stmt = conn.createStatement();  // non-tx statement

            // Check the database connection.
            try {
                stmt.executeUpdate("DROP TABLE test_table");
                stmt.executeUpdate("DROP TABLE test_table2");
            }
            catch (Exception e) {
                throw new RuntimeException(e);
                // assume not in database.
            }

            try {
                stmt.executeUpdate("CREATE TABLE test_table (a INTEGER,b INTEGER)");
                stmt.executeUpdate("CREATE TABLE test_table2 (a INTEGER,b INTEGER)");
            }
            catch (Exception e) {
                throw new RuntimeException(e);
            }

            try {
                System.out.println("Starting top-level transaction.");

                txn.begin();

                stmtx = conn.createStatement(); // will be a tx-statement

                // First, we try to roll back changes

                System.out.println("\nAdding entries to table 1.");

                stmtx.executeUpdate("INSERT INTO test_table (a, b) VALUES (1,2)");

                ResultSet res1 = null;

                System.out.println("\nInspecting table 1.");

                res1 = stmtx.executeQuery("SELECT * FROM test_table");

                while (res1.next()) {
                    System.out.println("Column 1: "+res1.getInt(1));
                    System.out.println("Column 2: "+res1.getInt(2));
                }
                System.out.println("\nAdding entries to table 2.");

                stmtx.executeUpdate("INSERT INTO test_table2 (a, b) VALUES (3,4)");
                res1 = stmtx.executeQuery("SELECT * FROM test_table2");

                System.out.println("\nInspecting table 2.");

                while (res1.next()) {
                    System.out.println("Column 1: "+res1.getInt(1));
                    System.out.println("Column 2: "+res1.getInt(2));
                }

                System.out.print("\nNow attempting to rollback changes.");

                txn.rollback();

                // Next, we try to commit changes
                txn.begin();
                stmtx = conn.createStatement();
                System.out.println("\nAdding entries to table 1.");
                stmtx.executeUpdate("INSERT INTO test_table (a, b) VALUES (1,2)");
                ResultSet res2 = null;

                System.out.println("\nNow checking state of table 1.");

                res2 = stmtx.executeQuery("SELECT * FROM test_table");

                while (res2.next()) {
                    System.out.println("Column 1: "+res2.getInt(1));
                    System.out.println("Column 2: "+res2.getInt(2));
                }

                System.out.println("\nNow checking state of table 2.");

                stmtx = conn.createStatement();

                res2 = stmtx.executeQuery("SELECT * FROM test_table2");

                while (res2.next()) {
                    System.out.println("Column 1: "+res2.getInt(1));
                    System.out.println("Column 2: "+res2.getInt(2));
                }

                txn.commit();
            }
            catch (Exception ex) {
                throw new RuntimeException(ex);

            }
        }
        catch (Exception sysEx) {
            sysEx.printStackTrace();
            System.exit(0);
        }
    }
}

11.8.2. Transaction API Documentation

The transaction JTA API documentation is available as Javadoc at the following location:

If you use Red Hat JBoss Developer Studio to develop your applications, the API documentation is included in the Help menu.

Red Hat logoGithubRedditYoutubeTwitter

Learn

Try, buy, & sell

Communities

About Red Hat Documentation

We help Red Hat users innovate and achieve their goals with our products and services with content they can trust.

Making open source more inclusive

Red Hat is committed to replacing problematic language in our code, documentation, and web properties. For more details, see the Red Hat Blog.

About Red Hat

We deliver hardened solutions that make it easier for enterprises to work across platforms and environments, from the core datacenter to the network edge.

© 2024 Red Hat, Inc.