There are three types of Java transactions: JDBC Transaction, JTA (Java Transaction API) transaction, container transaction.
A transaction is a uniform commit or rollback operation for a series of database operations (such as inserting multiple data), and if the insert succeeds, it succeeds, and if there is an exception in the middle, all actions before the rollback.
This prevents dirty data from occurring and prevents problems with database data. In development, transaction management is generally done to avoid this situation.
In JDBC, transaction management is done through the connection object.
Hibernate is a transaction management process through transaction, similar to that of JDBC.
Spring also has its own transaction management mechanism, typically managed using Transactionmananger, which can be done through spring injection.
Transaction management for JDBC
All JDBC behavior includes transaction is based on a connection, in JDBC is through the connection object for transaction management, the default is to automatically commit the transaction, you can manually turn autocommit off, commit through commit method, rollback method rollback , the data is not actually inserted into the database if it is not committed.
Based on the design idea of the Java EE layered architecture, the data access layer should specialize in data access, while business logic is processed in the business logic layer. To improve reuse, the granularity of the data Access Layer object (DAO) is usually very small, and an update operation is encapsulated in a method so that when there are multiple update operations that need to be bundled into a transaction, the processing of the transaction can only be implemented in the business logic layer.
in the case of non-layering, a typical JDBC transaction code snippet is as follows.
try {
Conn =drivermanager.getconnection
("Jdbc:oracle:thin: @host: 1521:sid", "username", "userpwd";
Conn.setautocommit (FALSE);//Prohibit auto-commit, set rollback point
stmt = Conn.createstatement ();
Stmt.executeupdate ("ALTER TABLE ..."); Database Update Operations 1
Stmt.executeupdate ("INSERT into Table ..."); Database Update Operations 2
Conn.commit (); Transaction commit
}catch (Exception ex) {
Ex.printstacktrace ();
try {
Conn.rollback (); Rollback if operation is unsuccessful
}catch (Exception e) {
E.printstacktrace ();
}
}
The JDBC transaction is controlled with the Connection object. The JDBC Connection Interface (java.sql.Connection) provides two transaction modes: Autocommit and Manual commit. Java.sql.Connection provides the following methods of controlling transactions:
public void Setautocommit (Boolean)
public boolean getautocommit ()
public void commit ()
public void rollback ()
When using JDBC transaction demarcation, you can combine multiple SQL statements into a single transaction. One drawback of JDBC transactions is that the scope of a transaction is limited to a single database connection. A JDBC transaction cannot span multiple databases.
Analysis of the security and efficiency of JDBC's transaction management
If the basic JDBC connection is used directly, it must be the safest to turn off the connection. If all the code shared a connection, there would be an efficiency problem, sometimes deadlocks, and connection was not thread-safe.
With no datasource and close connection not directly related. Using DataSource just to connection the creation of the solution out, can change. DataSource is an interface where the connection pool is used to return a connection proxy (or wrapper,delegate, etc.).when the Close method of this proxy is called, it is not closed directly, but the connection is put back into the connection pool.
At the same time, because a transaction needs to be guaranteed to use a connection, and if each invocation of DAO is simple to establish a connection from DataSource, there is no guarantee that the connection will be consistent and the efficiency may be problematic. Therefore, a better approach is to use threadlocal, call the unified method to establish a connection, the method first check whether there is a connection in the threadlocal, there is the use, no new, the connection put into the threadlocal.
How spring's Datasourceutil is written, that's the idea.Threadlocal is not a connection package, but a savepoint for connection. Using connection pooling does not guarantee that the connection you use is thread-consistent. The general connection pooling implementation does not care about this.
With transaction management code, when a transaction begins, a connection request is made to the connection pool, and then DAO does not request a connection directly to the connection pool but gets the connection in threadlocal, commits the transaction after the transaction ends, and closes connection (if the connection pool is used, The connection is returned to the transaction) so a transaction commit and connection shutdown code must be guaranteed. So the example code for spring is generally to put transaction management on the service layer, not the DAO layer.
Transaction management for JTA
The Java Transaction API (Jta;java Transaction API) of the EE platform provides distributed transaction services. A distributed transaction (distributed transaction) consists of a transaction manager (transaction manager) and one or more resource Managers (Resource Manager). A Resource Manager (Resource Manager) is any type of persisted data store. The transaction manager (transaction Manager) undertakes the responsibility of communicating with each other in the unit of the transaction. Shows the relationship between the transaction manager and resource management.
The
JTA transaction
jta (Java Transaction API) provides distributed transaction services for the EE platform.
To use jta for transaction demarcation, the application calls methods in the Javax.transaction.UserTransaction interface . For example:
import javax.transaction.*;
import javax.naming.*;
//...
InitialContext CTX = n EW InitialContext ();
Object txobj = Ctx.lookup ("; java:comp/usertransaction";);
UserTransaction UTX = (usertransaction) txobj;
Once the application has a reference to the UserTransaction object, it can start the transaction.
utx.begin ();
//...
DataSource ds = Obtainxadatasource ();
Connection conn = Ds.getconnection ();
pstmt = conn.preparestatement ("UPDATE MOVIES ...");
pstmt.setstring (1, "Spinal Tap");
pstmt.executeupdate ();
//...
utx.commit ();
Let's focus on the following:
"defines a transaction with JTA, then there needs to be an implementation The JDBC driver for the Javax.sql.XADataSource, Javax.sql.XAConnection, and Javax.sql.XAResource interfaces. A driver that implements these interfaces will be able to participate in the JTA transaction. A Xadatasource object is a factory of a Xaconnection object. Xaconnection S is a JDBC connection that participates in JTA transactions. "
To use JTA transactions, you must use Xadatasource to generate a database connection, resulting in a connection that is an XA connection. The difference between
xa connections (javax.sql.XAConnection) and non-XA (java.sql.Connection) connections is that XA can participate in JTA , and does not support auto-commit.
Note:
Large databases such as Oracle, Sybase, DB2, SQL Server support XA and distribute transactions.
My SQL even local support is not good, let alone distributed transactions.
implementation of the JTA method:
Xadatasource generated xaconnection it expands a Getxaresource () method, The transaction is managed in this way by adding it to the transaction container. For the caller, it is not possible to see that the transaction is managed, you just declare the transaction to start, tell the container that my operation requires the transaction to participate, and finally tell the transaction that it can be committed or rolled back, and that the other is a black box operation.
before using JTA, you must first implement a XID class to identify the transaction (which will normally be handled by the transaction management program). XID contains three elements: FormatID, Gtrid (global transaction Identifier), and bqual (branch modifier identifier).
The following example illustrates the implementation of XID:
Import javax.transaction.xa.*;
public class Myxid implements Xid
{
protected int FormatID;
protected byte gtrid[];
protected byte bqual[];
Public Myxid ()
{
}
Public Myxid (int formatid, byte gtrid[], byte bqual[])
{
This.formatid = FormatID;
This.gtrid = Gtrid;
This.bqual = bqual;
}
public int Getformatid ()
{
return FormatID;
}
Public byte[] Getbranchqualifier ()
{
return bqual;
}
Public byte[] Getglobaltransactionid ()
{
return Gtrid;
}
}
Second, you need to create a data source for the database you want to use:
Public DataSource Getdatasource ()
Throws SQLException
{
SQLServerDataSource xads = new
Com.merant.datadirect.jdbcx.sqlserver.SQLServerDataSource ();
Xads.setdatasourcename ("SQL Server");
Xads.setservername ("server");
Xads.setportnumber (1433);
Xads.setselectmethod ("cursor");
return xads;
}
Example 1? This example uses a "two-step commit protocol" to commit a branch of a transaction:
Xadatasource xads;
Xaconnection Xacon;
XAResource Xares;
Xid Xid;
Connection con;
Statement stmt;
int ret;
Xads = Getdatasource ();
Xacon = Xads.getxaconnection ("Jdbc_user", "Jdbc_password");
Xares = Xacon.getxaresource ();
con = xacon.getconnection ();
stmt = Con.createstatement ();
XID = new Myxid (New byte[]{0x01}, New byte[]{0x02});
try {
Xares.start (XID, xaresource.tmnoflags);
Stmt.executeupdate ("INSERT into test_table values (100)");
Xares.end (XID, xaresource.tmsuccess);
ret = Xares.prepare (XID);
if (ret = = XARESOURCE.XA_OK) {
Xares.commit (XID, false);
}
}
catch (Xaexception e) {
E.printstacktrace ();
}
finally {
Stmt.close ();
Con.close ();
Xacon.close ();
}
Of course, in practice, we don't need to write this code, which is the final implementation code of JTA.
For the two-step commit agreement, you can refer to the following article:
Http://www.ibm.com/developerworks/cn/db2/library/techarticles/dm-0505weber/index.html
Two-phase commit (TWO-PHASE-COMMIT) protocol
First, the start of a two-phase commit (Two-phase-commit) transaction is similar to a regular single-phase commit (One-phase-commit) transaction. The application/client then performs its modifications to all the databases involved in the two-phase commit (TWO-PHASE-COMMIT) operation. Now, before the transaction is finally committed, the client notifies the participating database that it is ready to commit (phase 1th). If the client receives a "Okay" from the database, it issues a command to submit the transaction to the database (phase 2nd). The last distributed transaction (distributed Transaction) ends.
The examples in this article demonstrate how to implement a two-phase commit (TWO-PHASE-COMMIT) protocol using JTA in Java. In this application, if a transaction branch reports an error, you are responsible for error handling. But there is still a problem in the "Introduction to two-phase commit protocol" subsection, that is, what happens if a branch of a transaction in phase 2nd fails?
If you look at the program code again, you can see that there is a very small interval between "phase 1th" and "phase 2nd". In this interval, one of the participating databases may crash for some reason. If this happens, we will be caught in a situation where the distributed transaction has been partially committed.
Assume the following scenario: After phase 1th, you receive "Okay" from both the DB2 and the IDS database. In the next step, the application successfully submitted the DB2 transaction branch. The application then notifies the DB2 transaction branch to commit the transaction. The IDs engine now crashes because of a power outage before the application can notify the IDS transaction branch to commit this part. This is a case where the global transaction is partially committed. What do you do now?
After the reboot, both DB2 and IDS will attempt to recover the open transaction branch. The engine waits for hints from the application to do. If the application is not ready to resend the "phase 2nd" commit, the transaction branch will be aborted by the exploratory rollback initiated by the engine. This is very bad, because this causes the global transaction to be in an inconsistent state.
One solution is to use a small application to connect the open transaction branch in the engine and inform the engine to commit or roll back the open transaction. If you use IDS as the backend, there is also a hidden Onmode flag that allows you to end an open transaction branch. (Onmode-z XID).
In DB2 UDB, you can issue a LIST INDOUBT transactions to get information about an open XA transaction. You must review the description in DB2 information Center to resolve the issue.
The scenario described above is a good example of the reason for using the application server (application server) or the transaction monitor (Transaction monitor). When using a middle-tier server, the server is responsible for keeping things normal.
Transaction management for JDBC, JTA, Spring