XA transaction processing

The XA protocol was first proposed by Tuxedo and handed over to the X/Open organization as an interface standard between resource managers (databases) and transaction managers. At present, major database manufacturers such as Oracle , Informix , DB2 and Sybase all provide support for XA. The XA protocol uses a two-phase commit method to manage distributed transactions . The XA interface provides a standard interface for communication between resource managers and transaction managers. The XA protocol includes two sets of functions, those beginning with xa_ and those beginning with ax_.

 

Introduction

edit
Depending on the context, XA has a variety of meanings. XA in our common database connection transactions refers to the specification of distributed transaction processing proposed by the X/Open organization. The XA specification mainly defines the transaction manager (Transaction Manager) and local Resources Manager (Local Resource Manager) interface. Some people say that XA is the abbreviation of eXtended Architecture, in fact, I think this is just a coincidence. eXtended Architecture is a CD ROM drive architecture.

XA operation

edit
The following functions enable the transaction manager to perform operations on the resource manager:
1) xa_open, xa_close: establish and close the connection with the resource manager.
2) xa_start, xa_end: start and end a local transaction .
3) xa_prepare, xa_commit, xa_rollback: pre-commit, commit and roll back a local transaction.
4) xa_recover: Roll back a transaction that has been pre-committed.
5) The functions at the beginning of ax_ enable the resource manager to dynamically register with the transaction manager and operate on XID (TRANSACTION IDS).
6) ax_reg, ax_unreg; allows a resource manager to dynamically register or unregister in a TMS (TRANSACTION MANAGER SERVER).

This article is selected from the fifth chapter of the mini-book "Java Transaction Design Strategies" , translated by Zhai Jing.

In order to illustrate the importance of the X/Open XA interface in JTA transaction management, and the timing of its use, let's take the EJB code of a fixed income transaction mentioned in the previous chapter as an example:

@TransactionAttribute(TransactionAttributeType.REQUIRED)

 public void placeFixedIncomeTrade(TradeData trade) throws Exception {
     try {
         ...
         Placement placement =  placementService.placeTrade(trade);
         executionService.executeTrade(placement);
     } catch (TradeExecutionException e) {
         log.fatal(e);
         sessionCtx.setRollbackOnly();
         throw e;
     }
 }         
 

In this code, a transaction is first provisioned and then executed, and these two operations change different tables in the database. As we saw in the previous chapter, this code is guaranteed to follow ACID guidelines in a standard non-XA environment. Suppose we receive a new requirement for a company to send a JMS message to other systems on every fixed income transaction to keep an eye on transaction activity. For simplicity, we also assume that all JMS message logic is implemented in the sendPlacementMessage() method. The above example is modified as follows to implement the new functionality:

@TransactionAttribute(TransactionAttributeType.REQUIRED)

public void placeFixedIncomeTrade(TradeData trade) throws Exception {
    try {
        ...
        Placement placement =  placementService.placeTrade(trade);
        placementService.sendPlacementMessage(placement);
        executionService.executeTrade(placement);
    } catch (TradeExecutionException e) {
        log.fatal(e);
        sessionCtx.setRollbackOnly();
        throw e;
    }
}

While the above modification is simple enough, this code does not guarantee ACID guidelines. If the executeTrade() method throws a TradeExecutionException, the database changes will be rolled back, but the trade preset message will be sent to the JMS queue or topic. In fact, the transaction preset message is likely to be released (consumed) by the queue or topic after the sendPlacementMessage() method is executed.

Because in a non-XA environment, the insertion process of the message queue is independent of the database update operation, the atomicity and independence in the ACID criterion cannot be guaranteed, and the overall data integrity is compromised. What we need is a way to keep the message queue and database under the control of a single transaction, so that the two resources can be coordinated to form a single unit of work. Using X/Open's XA interface, we are able to coordinate multiple resources and ensure that ACID guidelines are maintained.

Detailed explanation of XA interface

The X/Open XA interface is a bidirectional system interface that forms a communication bridge between the Transaction Manager and one or more Resource Managers. The transaction manager controls JTA transactions, manages the transaction lifecycle, and coordinates resources. In JTA, the transaction manager is abstracted as the javax.transaction.TransactionManager interface and implemented through the underlying transaction service (ie JTS). The resource manager is responsible for controlling and managing the actual resources (such as databases or JMS queues). The following diagram illustrates the relationship between transaction managers, resource managers, and client applications in a typical JTA environment:

Note that the XA interface in the above figure forms the communication bridge between the transaction manager and the resource manager. Because of the bidirectional nature of the XA interface, XA supports a two-phase commit protocol, which we will discuss later in this chapter.

It is difficult to cover all the details of the XA interface in what is described in this chapter. If readers care about the details of XA, please refer to the X/Open XA interface specification (available in pdf format at http://www.opengroup.org/onlinepubs/009680699/toc.pdf).

When should XA be used?

An often confusing question in Java transaction management is when to use XA and when not to use it. Since most commercial application servers perform one-phase commit operations, performance degradation is not a concern. However, unnecessary introduction of the XA database driver into your application can lead to unforeseen consequences and errors, especially when using the Local Transaction Model. So in general you should try to avoid XA when you don't need it. The following best practices describe when XA should be used:

Best Practices

The use of the X/Open XA interface is only necessary when multiple resources (ie databases, and message topics or queues) need to be coordinated within the same transaction context.

 

An important point here is that while your application may use multiple resources, it is only necessary to use XA if these resources must be coordinated within the same transaction scope. Multiple resource scenarios include accessing two or more databases (not just multiple tables, but multiple databases separated from each other), or a database plus a message queue, or multiple message queues. You may have an application that uses both a database and a message queue. However, if these resources are not used in the same transaction, there is no need to use XA. The code at the beginning of this chapter, which presets a fixed-income transaction and then sends a message to the queue, is an example of the need to use XA in order to maintain ACID properties.

The most common scenario where XA is required and used is to coordinate database changes and message queues (or topics) in the same transaction. Note that these two operations may appear in completely different places in the application (especially when using an ORM framework like hibernate). XA transactions must coordinate both types of resources when a rollback event occurs, or keep changes isolated from other transactions. Without XA, messages sent to the queue or topic would arrive and be read even before the transaction terminates. In the XA environment, the messages in the queue will not be released until the transaction is committed. Also, if you are reconciling an operational database and a read-only database (ie, the reference database), you don't need XA. However, since XA supports "read-only optimizations", you may not see any performance penalty when introducing a read-only data source into an XA transaction.

There are several implicit issues to consider when intending to use XA in your enterprise Java applications. These problems include two-phase commit (2PC, two-phase commit process), empirical anomalies, and the use of XA drivers. The following sections detail each of these issues.

two-phase commit

The two-phase commit protocol (2PC) is XA's mechanism for coordinating multiple resources in a global transaction. The two-phase protocol follows the OSI (Open System Interconnection)/DTP standard, although it appeared several years earlier than the standard itself. The two-phase commit protocol consists of two phases: the first phase (also called the preparation phase) and the second phase (also called the commit phase). A good analogy for describing a two-stage submission is a typical wedding ceremony, where each participant (the bride and groom in the wedding ceremony) must obey the arrangements and say "I do" before officially entering married life. Consider a cup situation where one of the "participants" backtracked at the last minute before making a commitment. The result of a two-phase commit here is also true, although not as disruptive.

When a commit() request is sent from the client to the transaction manager, the transaction manager begins the two-phase commit process. In the first phase, all resources are polled and asked if they are ready to submit jobs. Each participant may answer "ready (READY)", "read only (READ_ONLY)", or "not ready (NOT_READY)". If any participant responds "NOT_READY" in the first phase, the entire transaction is rolled back. If all participants answer "READY", then the resources are committed in the second phase. Resources that answer "READ_ONLY" are excluded from the second phase of the protocol.

Two-phase commit becomes possible due to the ability of two-way communication in the XA environment. In a non-XA transactional environment, the communication is only one-way, and two-phase commit cannot be done because the transaction manager cannot receive a response from the resource manager. In order to optimize performance and release resources as soon as possible, most transaction managers use multithreading to handle the first-phase polling and second-phase commit processes. The following diagram shows the basic flow of a two-phase commit:

The following diagram shows the process of two-phase commit when one of the resource managers (DBMS) has an error while polling in the first phase,

In this example, a commit request is sent to the transaction manager by a client running a global transaction (a JTA transaction running under XA). In the first phase, the second resource manager returns a "NOT_READY" response to the transaction manager. In this case the transaction manager issues a rollback request to all participants, thus coordinating all resources in the global transaction.

Some commercial application containers provide a feature called "Last Participant Support", which has another name called "Last Resource Commit Optimization". "Last Participant Support" allows non-XA resources to participate in global transactions. Under "Last Participant Support", when a commit request from an XA environment reaches the transaction manager, the transaction manager will first initiate a first-stage process for the XA resource. Once the results generated by the XA participants are returned consistently, the transaction manager then initiates a commit (or rollback) request to the non-XA participants. The outcome of this request determines how the rest of the two-phase commit process works. If the request for the non-XA resource is successful, the transaction manager initiates the second phase and initiates a commit request to the XA participant. If a request to a non-XA participant is unsuccessful, the transaction manager initiates a second phase and asks all XA participants to roll back the transaction.

There are two problems with the "Last Participant Support" mechanism. First, it is not portable across application containers. Second, because there is a long wait between the first-stage polling process and the non-XA last participating in the resource submission, you will find that you have an increased chance of a Heuristic Exception when using this feature (will detailed in the next section). For these reasons, the "Last Participant Support" feature should generally be avoided unless absolutely necessary.

Most commercial application servers also support another optimization called "One-Phase Commit Optimization". If the transaction includes only one participant, the first phase of processing is ignored and the single participant is notified to commit. In this case, the consequences of the entire XA transaction depend on the outcome of a single participant.

Heuristic Exception handling

In a two-phase commit process, the resource manager may use an "empirical decision" strategy to either commit or roll back its own work, without the transaction manager's control. "Empirical decision making" refers to the process of making intelligent decisions based on a variety of internal and external factors. When the resource manager does this, it reports a Heuristic Exception to the client.

Fortunately, empirical anomalies are not particularly common. It only happens in an XA environment during a two-phase commit, especially after the transaction participant has responded in the first phase. The most common cause of experience anomalies is a timeout condition between the first and second phases. When communication is delayed or lost, the resource manager may make a decision to commit or roll back its work to free up resources. Unsurprisingly, the most frequent occurrences of experience anomalies are periods of high resource utilization. When you find experience anomalies in your application, you should look for transaction timeout issues, resource locking issues, and resource overcommitment, which are often the root cause of experience anomalies. Occasional network delays or network failures can also lead to anomalous experiences. Also, using the "Last Participant Support" feature, as described in the previous section, will result in more frequent occurrences of experiential anomalies.

The three JTA experience exceptions exposed by JTA are HeuristicRollbackException, HeuristicCommitException, and HeuristicMixedException. We illustrate it with the following scenarios:

Scenario 1 : HeuristicRollbackException during commit operation phase

In this scenario, the client performs the update operation in the XA environment and initiates a request to submit the current transaction to the transaction manager. The transaction manager initiates the first phase of the two-phase commit process and then polls the resource manager. All resource managers report to the transaction manager that they are ready to commit transactions. However, between the first and second phases (of the two-phase commit process) each resource manager independently makes an empirical decision to roll back their completed work. When entering the second stage, when the commit request is sent to the resource manager, the transaction manager will report a HeuristicRollbackException to the caller because the work has been rolled back before that.

When such an exception is received, the usual correct way to handle it is to pass the exception back to the client and let the client resubmit the request. We cannot simply call the commit request again, because the update to the database has already been removed from the database transaction log with the rollback. The following sequence diagram illustrates this scenario:

Step 1: The first stage of processing (preparation stage)

Step 2: Between Phase 1 and Phase 2

Step 3: Phase 2 Processing (Submit Phase)

As you can see from the sequence diagram, both resource managers rolled back their own work, although they both reported a READY response to the transaction manager in the first phase. Don't worry about why these exceptions occur, we will delve deeper into them in subsequent chapters.

Scenario 2 : HeuristicMixedException in commit operation phase

In this scenario, the client performs the update operation in the XA environment and initiates a request to submit the current transaction to the transaction manager. The transaction manager initiates the first phase of the two-phase commit process and then polls the resource manager. All resource managers report to the transaction manager that they are ready to commit transactions. Unlike the first scenario, in the gap between the first and second phases, some resource managers (such as message queues) make an empirical decision to submit their work, while other resource managers (such as databases) An empirical decision to roll back was made. In this case, the transaction manager reports a HeuristicMixedException to the caller.

In this case, it is very difficult to choose the correct follow-up response, because we do not know which resources committed the work and which resources rolled back the work. All target resources are therefore in an inconsistent state. Because the resource managers operate independently of each other, there is no coordination or communication between them as far as empirical decisions are concerned. Resolving this anomaly usually requires human intervention. The following sequence diagram illustrates this scenario:

Step 1: The first stage of processing (preparation stage)

Step 2: Between Phase 1 and Phase 2

Step 3: Phase 2 Processing (Submit Phase)

Note that in the illustration above, one resource manager committed its work, while the other resource managers chose to roll back their work. In this case the transaction manager will report a HeuristicMixedException.

Using XA with message queues or topics

The resources used under the XA interface must implement the javax.transaction.xa.XAResource interface so that they can join the XA global transaction. For JMS destinations (queues or topics), this can be done by configuring in a specific application server console or hypervisor. The part that really activates XA is the JMS Connection Factory. Once the JMS connection factory supports XA, messages sent to a JMS queue or topic will not be released until the two-phase commit process is complete. In the absence of XA, messages sent to JMS destinations are immediately released and can be picked up by receivers, regardless of the transaction context in which they result.

In the WebLogic application server, XA's JMS connection factories can be activated in the Services|JMS|Connection Factories configuration in the Administration Console. On the Transactions page, there is an option called XA Connection Factory Enabled, through which JMS targets can be included in JTA global transactions. For IBM WebSphere, the JMS Connection Factories feature using XA can be selected in the Administrative Console under the Resources|WebSphere JMS Providers|Connection Factories path. Checking the checkbox named EnableXA activates the XA JMS connection factory.

Use XA for the database

Databases can be made to support XA by using the XA version of the database driver. Since the XA version of the database driver is usually much harder to use than the non-XA version, one piece of advice is not to use the XA driver unless you have to.

Using the XA version of the database driver often results in unexpected and difficult-to-solve errors. For example, replacing a non-XA driver with an XA version often produces bugs that are hard to track down. Therefore, XA drivers should be introduced as early as possible in the project development and testing phase (to expose problems and solve them early).

When using the XA version of the database driver, the types of errors that may be encountered include local transaction errors and nested transaction errors. These errors occur when you attempt to start a new transaction while an XA global transaction is in progress. This situation can occur in multiple contexts, but the most common situation is caused by mixing the local transaction model with the declarative transaction model, and the use of stored procedures in an XA environment.

When using stored procedures in an XA environment, calling DDL (data definition statements, such as CREATE TABLE, BEGIN TRAN, END TRAN) in a stored procedure often results in errors. This is the most frequent culprit for XA errors and is very difficult to fix. For example in Oracle, when using XA, you may see the following error message:

ORA-02089: COMMIT is not allowed in a subordinate session

If you are using a non-XA database driver, you probably won't see this error because the JTA transaction is suspended while the DDL statement is executing. When you see this error message, it means that your stored procedure contains DDL code and the local transaction (managed by the resource manager) is trying to commit its work.

It is often difficult to remove existing DDL statements from stored procedures, because they must have a reason to exist there, or perhaps the stored procedures are shared by other applications (it would be too much to remove them). An effective way to circumvent the problem is to manually suspend the transaction before calling these stored procedures; and continue the transaction after the stored procedures return. Using this trick will avoid XA related local and nesting errors. However, if you do this, the changes made by the stored procedure are committed independently of the JTA global transaction, thus violating the ACID properties of transactions. So, this approach is only to circumvent the problem, not to solve it. The following code snippet shows the details of this technique:

...
InitialContext ctx = new InitialContext();
TransactionManager tm = (javax.transaction.TransactionManager)
ctx.lookup(“javax.transaction.TransactionManager”);
Transaction currentTx = null;

try {
    currentTx = tm.suspend();
    invokeSPWithDDL();
} finally {
    if (currentTx != null)
    tm.resume();
}

Even in the context of declarative transactions, we can still use the TransactionManager to suspend and resume transactions in code. This trick can avoid the SQL exception message in the XA environment, but it doesn't really solve the problem. - The only way to really solve the problem is to remove those foul DDL statements in the concerned stored procedure, or to use the JTA transaction service which supports nested transactions.

Summarize

The most important idea to express in this chapter is to understand when you really need to use the XA version of the database driver. Many developers and architects have always insisted on using the XA version of the database driver, despite the fact that there is no legitimate reason to use them. If you need to coordinate multiple changed resources (databases, message queues, topics, or JCAs) in the same transaction, then there is no doubt that you need to introduce the XA interface. Otherwise, definitely avoid XA.

Another piece of advice about using XA is to not always guess that you are using a possibly buggy XA database driver when you run into problems. The problem is most likely your application code or transaction logic, not the XA driver.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326686220&siteId=291194637