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
andXAResource
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
andXAResource
DataSource
that is completely visible to the application layer. Use it to operateXADataSource
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:
- Client
- A middle tier containing a collection of applications, EJB servers, and JDBC drivers
- 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:
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.
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();
- The application server passes the
XAResource
object to the transaction manager, and the transaction manager does not directlyXAConnection
object. 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);
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
.
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);
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.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。