So far, discussions about transactions have basically focused on local transactions, which only involve a single data source. This chapter begins with an introduction to distributed transactions, which involve multiple data sources within a single transaction. The following content mainly includes:

  • Distributed knowledge transaction infrastructure
  • Transaction manager and resource manager
  • XADataSource , XAConnection and XAResource interfaces
  • Two-phase commit

The transaction management API of JDBC is compatible with the JTA specification.

infrastructure

The infrastructure of distributed transactions includes the following parts:

  • The transaction manager is used to control the boundary of the transaction and manage the two-phase commit protocol. It should also be a classic implementation of JTA.
  • Implemented JDBC drivers XADataSource , XAConnection and XAResource
  • DataSource that is completely visible to the application layer. Use it to operate XADataSource and interact with the transaction manager. Usually this implementation is provided by the application server.
  • The resource manager used to manage the underlying data. In the context of JDBC, the resource manager refers to the database server. The term "resource manager" actually comes from JTA. This term is used here to emphasize that distributed transactions in JDBC are processed in accordance with the JTA specification.

This infrastructure is usually implemented in a "three-tier architecture", including:

  1. Client
  2. A middle tier containing a collection of applications, EJB servers, and JDBC drivers
  3. Multiple resource managers

Distributed transactions can also be implemented as a "two-tier architecture." In the two-tier architecture, the application layer itself will play the role of the transaction manager and directly operate the XADataSource API. The following figure illustrates the infrastructure of distributed transactions:

image-20210613150204476

The following content will give a detailed description of each part of the infrastructure

XADataSource and XAConnection

XADataSource and XAConnection interfaces are defined in the javax.sql package. Database drivers supporting distributed transactions need to implement these two interfaces. XAConnection inherits the PooledConnection interface and adds a getXAResource method. This method will generate a XAResource object. The transaction manager can use this object to complete distributed transactions. The following is the definition XAConnection

public interface XAConnection extends PooledConnection {
javax.transaction.xa.XAResource getXAResource() 
throws SQLException;
}

Because it inherits the PooledConnection interface, all XAConnection objects also support the methods defined in PooledConnection These objects represent a reusable physical connection with the underlying data source, and the application layer can also manipulate this connection through this object.

XAConnection object is generated XADataSource ConnectionPoolDataSource and XADataSource have some similarities, they both implement the DataSource interface. This allows the underlying implementation of distributed transactions to be transparent to the application layer. XADataSource interface is defined as follows:

public interface XADataSource {
XAConnection getXAConnection() throws SQLException;
XAConnection getXAConnection(String user, 
String password) throws SQLException;
//...
}

Typically, it based XADataSource above DataSource achieved, also comprising a connection module pooled.

Deploy the XADataSource object

Deploying a XADataSource is the same as the previously mentioned ConnectionPoolDataSource The process is divided into two steps in total, as shown in the following code:

// com.acme.jdbc.XADataSource implements the 
// XADataSource interface.
// Create an instance and set properties.
com.acme.jdbc.XADataSource xads = new com.acme.jdbc.XADataSource();
xads.setServerName(“bookstore”);
xads.setDatabaseName(“bookinventory”);
xads.setPortNumber(9040);
xads.setDescription(“XADataSource for inventory”);
// First register xads with a JNDI naming service, using the
// logical name “jdbc/xa/inventory_xa”
Context ctx = new InitialContext();
ctx.bind(“jdbc/xa/inventory_xa”, xads);
// Next register the overlying DataSource object for application
// access. com.acme.appserver.DataSource is an implementation of
// the DataSource interface.
// Create an instance and set properties. 
com.acme.appserver.DataSource ds = 
new com.acme.appserver.DataSource();
ds.setDescription(“Datasource supporting distributed transactions”);
// Reference the previously registered XADataSource
ds.setDataSourceName(“jdbc/xa/inventory_xa”);

// Register the DataSource implementation with a JNDI naming service,
// using the logical name “jdbc/inventory”.
ctx.bind(“jdbc/inventory”, ds);

Get connection

Call the DataSource.getConnection method to return a logical Connection object whose underlying implementation is XAConnection:

Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup(“jdbc/inventory”);
Connection con = ds.getConnection(“myID”,“mypasswd”);

The underlying implementation of the DataSource.getConnection method is as follows:

// Assume xads is a driver’s implementation of XADataSource
XADataSource xads = (XADataSource)ctx.lookup(“jdbc/xa/" +
"inventory_xa”);
// xacon implements XAConnection
XAConnection xacon = xads.getXAConnection(“myID”, “mypasswd”);
// Get a logical connection to pass back up to the application
Connection con = xacon.getConnection();
CODE EXAMPLE 12-5 Getting a logical connection from an

XAResource

XAResource interface is a definition in the JTA specification and the equivalent concept of XA corresponding to the X/Open organization in the Java language. XAResource object is obtained by calling the XAConnection.getXAResource XAConnection to a distributed transaction by calling this method. At the same time, a XAConnection can only be bound to a distributed transaction. The JDBC driver should maintain XAResource and XAConnection , which means that multiple calls to the getXAResource method will return the same XAResource object.

Usually, after the intermediate application server calls the XAConnection.getXAResource method to obtain a XAResource object, it will hand it to the external transaction manager. The transaction manager does not need to directly XAConnection , it directly uses the XAResource object.

The transaction manager manages multiple XAResource objects, each of which represents a resource manager participating in a distributed transaction. Note that different XAResource objects may point to the same resource manager. When different transaction participants use the same XADataSource , then This may happen.

XAResource defines the following methods to complete the two-phase commit protocol. Each method requires an xid parameter to identify a distributed transaction.

  • start method. Notify the resource manager that subsequent operations are in a distributed transaction.
  • end method. Notify the resource manager of the end of the transaction.
  • prepare method. Get the resource manager's vote on whether the transaction should be rolled back or committed.
  • commit method. Notify the resource manager to commit its transaction branch. This method can only be called when all participants have voted to commit the global transaction.
  • rollback method. Notify the resource manager to roll back its transaction branch. This method will only be called when at least one transaction participant votes to roll back the global transaction.

There is a complete description of XAResource in the JTA specification.

Transaction management

Through the XAResource.start and XAResource.end methods to define the transaction boundary. The transaction mode within the boundary is a global transaction. Transactions outside the boundary are local affairs.

Except for some constraints, how a transaction participant's application code should be written has nothing to do with whether it participates in a distributed transaction. The boundaries of distributed transactions are generally defined by external transaction managers. Participants of the transaction cannot call some methods of the Connection

  • setAutoCommit(true)
  • commit
  • rollback
  • setSavepoint

If a transaction participant tries to call these methods, the JDBC driver should throw SQLException . When the distributed transaction is over, the call of these methods is no longer restricted and applies to local transactions.

Within the transaction boundary, transaction participants should avoid calling the Connection.setTransactionIsolation method. The behavior of this method is not restricted and is determined by the driver.

If a connection's autocommit attribute is true before participating in a distributed transaction, then this attribute will be ignored when it participates in a distributed transaction, and the attribute will take effect again after the transaction ends.

Two-phase commit

The following steps illustrate how the transaction manager uses the XAResource object to implement the two-phase commit protocol. These steps are based on a "three-tier architecture" using an application server with an external transaction manager.

  1. The application server gets the XAResource object from two different connections

    // XAConA connects to resource manager A
    javax.transaction.xa.XAResource resourceA = XAConA.getXAResource();
    // XAConB connects to resource manager B 
    javax.transaction.xa.XAResource resourceB = XAConB.getXAResource();
  2. The application server passes the XAResource object to the transaction manager, and the transaction manager does not directly XAConnection object.
  3. The transaction manager uses XAResource incorporate the resource manager into the transaction. The entire transaction is identified by an xid, which is generated when the transaction manager starts the transaction.

    // Send work to resource manager A. The TMNOFLAGS argument indicates
    // we are starting a new branch of the transaction, not joining or 
    // resuming an existing branch. 
    resourceA.start(xid, javax.transaction.xa.TMNOFLAGS);
    // do work with resource manager A
    ...
    // tell resource manager A that it’s done, and no errors have occurred 
    resourceA.end(xid, javax.transaction.xa.TMSUCCESS);
    // do work with resource manager B.
    resourceB.start(xid, javax.transaction.xa.TMNOFLAGS);
    // B’s part of the distributed transaction
    ...
    resourceB.end(xid, javax.transaction.xa.TMSUCCESS);
  4. The transaction manager initiates a two-phase commit protocol, requesting two participants to vote:

    resourceA.prepare(xid);
    resourceB.prepare(xid);

If a transaction participant wants to vote rollback, it needs to throw a javax.transaction.xa.XAException .

  1. If both transaction participants vote to commit, the transaction participant informs both participants to commit their transaction branch:

    resourceA.commit(xid, false);
    resourceB.commit(xid, false);
  2. If any transaction participant votes to rollback, the transaction manager informs each participant to roll back their transaction branch:

    resourceA.rollback(xid);
    resourceB.rollback(xid);

When the transaction manager processes different stages of a transaction branch, it does not necessarily use the same XAResource object, as long as the connection between the two objects comes from the same transaction manager.

Connection closed

When in a distributed transaction environment, the application layer uses up a connection, the middle-tier server should be notified. In the previous PooledConnection object, we pointed out that when the Connection.close method is called, the middleware server will be notified ConnectionEventListener At this time, the transaction manager will also be notified and end the corresponding transaction branch. If DataSource contains a pooling module, then the pooling module must also be notified in order to return XAConnection

Note that even if a connection is closed, distributed transactions can still be active.

Limitations of the XAResource interface

XAResource interface only defines the methods required to be defined in the X/Open XA specification. If a resource manager supports some features that are not defined in the XA specification, then the application layer cannot obviously use these features through the API, and can only be handled by the specific driver at the bottom layer. If the application indirectly utilizes this feature, it will bring a portability problem.


ytbean
3.1k 声望714 粉丝

十年学会编程


引用和评论

0 条评论