Comprehensive analysis of JTA depth Adventure

What is transaction processing

Transaction is an indispensable component model in computer applications. It ensures the atomicity, consistency, isolation and persistence of user operations. The most classic example of transaction is credit card transfer: transfer RMB 500 from user a's account to user B's account. The operation process is as follows:

1. Reduce the amount in account a by 500

2. Increase the amount in account B by 500

These two operations must correct the transaction attribute of acid: either all succeed or all fail; If there is no transaction guarantee, the user's account amount may have problems:

If the first step is successful and the second step fails, Then, the amount in user a's account will be reduced by 500 yuan, but the account number of user B will not be increased (missing); similarly, if the first step is wrong and the second step is successful, the account amount of user a will remain unchanged and the account number of user B will be increased by 500 yuan (born out of thin air). Any of the above errors will cause serious data inconsistency. The lack of transactions is unacceptable for a stable production system. J2EE transaction processing method

1. Local transaction: it is closely dependent on the underlying resource manager (such as database connection), and the transaction processing is limited to the current transaction resources. This transaction processing method does not depend on the application server, so it is flexible to deploy but can not support distributed transactions with multiple data sources. An example of using local transactions in a database connection is as follows:

Listing 1 Local transaction instance

2. Distributed transaction processing: Java transaction programming interface (JTA: Java transaction API) and Java transaction service (JTS; Java transaction service) provide distributed transaction services for J2EE platform. Distributed transaction includes transaction manager and one or more resource managers supporting XA protocol. We can think of a resource manager as any type of persistent data store; The transaction manager is responsible for the coordination and control of all transaction participating units. JTA transaction effectively shields the underlying transaction resources, so that applications can participate in transaction processing in a transparent way; However, compared with local transactions, XA protocol has a large system overhead. In the process of system development, we should carefully consider whether distributed transactions are really needed. If distributed transactions are really needed to coordinate multiple transaction resources, the transaction resources supporting XA protocol, such as JMS, JDBC database connection pool, etc., should be implemented and configured. An example of using JTA to process transactions is as follows (Note: conna and connb are connections from different databases)

Listing 2 JTA transaction

JTA implementation principle

Many developers will be interested in the internal working mechanism of JTA: the code I write does not have any code that interacts with transaction resources (such as database connections), but my operation (database update) is actually included in transactions. How does JTA achieve this transparency? To understand the implementation principle of JTA, we first need to understand its architecture: it includes transaction manager and one or more resource managers supporting XA protocol, We can think of a resource manager as any type of persistent data store; The transaction manager is responsible for the coordination and control of all transaction participating units. Depending on the object-oriented, We can understand the transaction manager and resource manager of JTA as two aspects: the use interface for developers (transaction manager) and the implementation interface for service providers (Resource Manager). The main part of the development interface is the UserTransaction object referenced in the above example. Developers implement distributed transactions in the information system through this interface, and the implementation interface is used to standardize providers (e.g. database connection provider) provides transaction services, which stipulate the resource management function of transactions, so that JTA can perform collaborative communication between heterogeneous transaction resources. Taking database as an example, IBM provides a database driver to realize distributed transactions, Oracle also provides a database driver to realize distributed transactions, and DB2 and or are used at the same time When two databases are connected, JTA can coordinate two transaction resources according to the agreed interface, so as to realize distributed transactions. It is the different implementations based on the unified specification that enable JTA to coordinate and control the transaction resources of different databases or JMS manufacturers.

Developers use the developer interface to realize the application's support for global transactions; Each provider (database, JMS, etc.) provides transaction resource management function according to the specification of provider interface; transaction manager (transactionmanager) maps the application's use of distributed transactions to the actual transaction resources, and coordinates and controls the transaction resources. Next, this paper will introduce the three main interfaces including UserTransaction, transaction and transactionmanager and their defined methods.

The developer oriented interface is UserTransaction (as shown in the above example). Developers usually only use this interface to realize JTA transaction management. It defines the following methods:

Begin () - start a distributed transaction (in the background, the transaction manager will create a transaction transaction object and associate this object to the current thread through threadlocale)

Commit () - commit the transaction (in the background, the transaction manager will take out the transaction object from the current thread and commit the transaction represented by this object)

Rollback () - rollback the transaction (in the background, the transaction manager will fetch the transaction object from the current thread and roll back the transaction represented by this object)

Getstatus () - returns the status of the distributed transaction associated with the current thread (all transaction statuses are defined in the status object. Interested readers can refer to the API documentation)

Setrollbackonly() - identifies that the distributed transaction associated with the current thread will be rolled back

The provider oriented implementation interface mainly involves two objects: transactionmanager and transaction

Transaction represents a physical transaction when the developer calls UserTransaction When using the begin () method, the transactionmanager will create a transaction transaction object (marking the beginning of the transaction) and associate this object with the current thread through threadlocale. Methods such as commit(), rollback(), getstatus() in the UserTransaction interface will be finally delegated to the corresponding method of the transaction class for execution. The transaction interface defines the following methods:

Commit () - coordinate different transaction resources to jointly complete the transaction submission

Rollback () - coordinate different transaction resources to complete transaction rollback

Setrollbackonly() - identifies that the distributed transaction associated with the current thread will be rolled back

Getstatus () - returns the status of the distributed transaction associated with the current thread

Enlistresource (xaresource, xares, int flag) - add the transaction resource to the current transaction (in the above example, the transaction resource represented by database a will be associated with the current transaction, similarly, the transaction resource represented by database B will also be associated with the current transaction) delistresource (xaresource, xares, int flag) -Delete the transaction resource from the current transaction

Registersynchronization (synchronization sync) - callback interface, hibernate and other ORM tools have their own transaction control mechanism to ensure transactions, but they also need a callback mechanism to be notified when the transaction is completed, so as to trigger some processing work, such as clearing the cache. This involves the transaction callback interface registersynchronization. The tool can inject the callback program into the transaction through this interface. When the transaction is successfully committed, the callback program will be activated.

Transaction manager itself does not undertake the actual transaction processing function. It acts more as a bridge between the user interface and the implementation interface. The methods defined in the transactionmanager are listed below. You can see that most of the transaction methods in this interface are the same as UserTransaction and transaction. When the developer calls UserTransaction When using the begin () method, transactionmanager will create a transaction object (marking the beginning of the transaction) and associate this object with the current thread through threadlocale; similarly, UserTransaction. Commit () will call transactionmanager The commit() method will take the transaction object transaction from the current thread and commit the transaction represented by this object, that is, call transaction commit()

Begin () - start transaction

Commit () - commit the transaction

Rollback () - rollback transaction

Getstatus () - returns the current transaction status

setRollbackOnly()

Gettransaction () - returns the transaction associated with the current thread

Settransactiontimeout (int seconds) - sets the transaction timeout

Resume (transaction toBJ) - continues the transaction associated with the current thread

Suspend () - suspend the transaction associated with the current thread

In the process of system development, you will encounter operations that need to temporarily exclude transaction resources. At this time, you need to call the suspend () method to suspend the current transaction: any operations after this method will not be included in the transaction, Call resume () to continue transactions after the non transactional operation is completed. Note: to do this, you need to get TransactionManager objects, which are different on different J2EE application servers.

Listing 3 Start transaction - usertransactionimpl implements UserTransaction

Listing 4 Start transaction - transactionmanagerimpl implements transactionmanager

Now we can understand why the begin method is not defined on the transaction interface: the transaction object itself represents a transaction. When it is created, it indicates that the transaction has started. Therefore, there is no need to define the begin () method.

Listing 5 Commit transaction - usertransactionimpl implements UserTransaction

Listing 6 Commit transaction - transactionmanagerimpl implements transactionmanager

Similarly, rollback, getstatus, setrollbackonly and other methods are implemented in the same way as commit (). The UserTransaction object does not have any control over the transaction. All transaction methods are passed to the actual transaction resource, the transaction object, through the transactionmanager.

The above example demonstrates the processing of JTA transactions. The following will show you how transaction resources (database connection, JMS) are added to JTA transactions in a transparent manner. First, it should be clear that the database source obtained in JTA transaction code must support distributed transactions. In the following code example, although all database operations are included in the JTA transaction, because the database connection of MySQL is obtained locally, any updates to MySQL will not be automatically included in the global transaction.

Listing 7 JTA transaction

Why must a database connection from a data source that supports transactions support distributed transactions? In fact, the data source supporting transactions is different from ordinary data sources. It implements an additional xadatasource interface. We can simply understand xadatasource as an ordinary data source (inherits java.sql.pooledconnection), but it adds the getxaresource method to support distributed transactions. In addition, the database connection returned by xadatasource is also different from the ordinary connection. In addition to realizing all the functions defined by java.sql.connection, this connection also implements the xaconnection interface. We can understand xaconnection as ordinary Database connection, which supports database operations of all JDBC specifications. The difference is that xaconnection adds support for distributed transactions.

The database connection obtained by the application from the data source supporting distributed transactions is the implementation of the xaconnection interface, and the session (statement) created by the database connection also adds functions to support distributed transactions, as shown in the following code:

Listing 8 JTA transaction resource processing

Let's look at the code implementation of the statement part created by the xaconnection database connection (different JTA providers have different implementation methods. The code example here just shows you how transaction resources are automatically added to the transaction). We take the execute method of the session object as an example. By adding a call to the associatewithtransactionifnecessary method at the beginning of the method, we can ensure any database connection during the JTA transaction All operations will be transparently added to the transaction.

Listing 9 Automatically associate transaction resources to transaction objects - xastatement implements statement

Xaresource and XID: xaresource is the Java implementation of the distributed transaction processing: the XA specification standard. It is an abstraction of the underlying transaction resources and defines the protocol between the transaction manager and the resource manager in the process of distributed transaction processing, Various transaction resource providers (such as jdbc driver and JMS) will provide the implementation of this interface. Using this interface, developers can implement distributed transaction processing through their own programming, but these are usually implemented by the application server (the server's own implementation is more efficient and stable). For illustration, we will illustrate its use.

Before using distributed transactions, in order to distinguish transactions and avoid confusion, an XID class must be implemented to identify transactions. You can think of XID as a transaction identifier. Each time a new transaction is created, an XID will be assigned to the transaction. XID contains three elements: formatid Gtrid (global transaction identifier) and bqal (branch modifier identifier). Formatid is usually zero, which means you will use OSI CCR (Open Systems Interconnection commitment, concurrency and recovery standards); if you want to use another format, the formatid should be greater than zero, and the value of - 1 means that XID is invalid. Gtrid and bqual contain 64 byte binary codes to identify global and branch transactions respectively. The only requirement is that gtrid and bqual must be global unique One.

The xaresource interface mainly defines the following methods:

Commit () - commit the transaction

Issamerm (xaresource xares) - check whether the current xaresource and parameter are the same transaction resource

Prepare () - notifies the resource manager to prepare the commit of the transaction

Rollback () - notifies the resource manager to roll back the transaction

When a transaction is committed, the Transaction object collects all the XAResource resources contained in the current transaction, and then calls the method of committing the resource, as shown in the following code:

Listing 10 Commit transaction - transactionimpl implements transaction

Conclusion

Through the above introduction, I believe that readers have already understood the principle of JTA, and the sample codes in this article are hypothetical implementations under ideal conditions. A perfect and mature JTA transaction implementation needs to consider and deal with many details, For example, performance (multithreading concurrent transaction submission when submitting transactions), fault tolerance (network, system exceptions), etc. it also takes a long time to mature. Interested readers can read some open source JTA implementations for further in-depth study. I hope this article can be helpful to you.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>