更新时间:2021-08-17 10:49:07 来源:动力节点 浏览902次
分布式事务通常涉及到同一数据源或不同数据源的多个连接,其中可能包括来自不同制造商的数据源。
演示分布式事务的最佳方式是将它们与本地事务进行对比。对于本地事务,JDBC应用程序对数据库进行永久性更改,并通过以下方式之一指示工作单元的结束:
通过在执行一个或多个SQL语句后调用Connection.commit或Connection.rollback方法
通过在应用程序开始时调用Connection.setAutoCommit(true)方法在每个SQL语句之后提交更改
图 1概述了执行本地事务的代码。
图 1. 本地事务示例
con1.setAutoCommit(false); // Set autocommit off
// execute some SQL
…
con1.commit(); // Commit the transaction
// execute some more SQL
…
con1.rollback(); // Roll back the transaction
con1.setAutoCommit(true); // Enable commit after every SQL statement
…
// Execute some more SQL, which is automatically committed after
// every SQL statement.
相反,参与分布式事务的应用程序不能在分布式事务中调用Connection.commit、Connection.rollback或Connection.setAutoCommit(true)方法。对于分布式事务,Connection.commit或Connection.rollback方法不指示事务边界。相反,您的应用程序让应用程序服务器管理事务边界。
图 2演示了一个使用分布式事务的应用程序。在示例中的代码运行时,应用程序服务器也在执行属于同一分布式事务的其他EJB。当所有EJB都调用utx.commit() 时,整个分布式事务由应用程序服务器提交。如果任何EJB不成功,应用程序服务器将回滚与分布式事务相关联的所有EJB所做的所有工作。
图 2. 应用服务器下的分布式事务示例
javax.transaction.UserTransaction utx;
// Use the begin method on a UserTransaction object to indicate
// the beginning of a distributed transaction.
utx.begin();
…
// Execute some SQL with one Connection object.
// Do not call Connection methods commit or rollback.
…
// Use the commit method on the UserTransaction object to
// drive all transaction branches to commit and indicate
// the end of the distributed transaction.
utx.commit();
…
图 3说明了一个使用JTA方法执行分布式事务的程序。该程序充当事务管理器和事务应用程序。到两个不同数据源的两个连接在单个分布式事务下执行SQL工作。
图 3. 使用JTA的分布式事务示例
class XASample
{
javax.sql.XADataSource xaDS1;
javax.sql.XADataSource xaDS2;
javax.sql.XAConnection xaconn1;
javax.sql.XAConnection xaconn2;
javax.transaction.xa.XAResource xares1;
javax.transaction.xa.XAResource xares2;
java.sql.Connection conn1;
java.sql.Connection conn2;
public static void main (String args []) throws java.sql.SQLException
{
XASample xat = new XASample();
xat.runThis(args);
}
// As the transaction manager, this program supplies the global
// transaction ID and the branch qualifier. The global
// transaction ID and the branch qualifier must not be
// equal to each other, and the combination must be unique for
// this transaction manager.
public void runThis(String[] args)
{
byte[] gtrid = new byte[] { 0x44, 0x11, 0x55, 0x66 };
byte[] bqual = new byte[] { 0x00, 0x22, 0x00 };
int rc1 = 0;
int rc2 = 0;
try
{
javax.naming.InitialContext context = new javax.naming.InitialContext();
/*
* Note that javax.sql.XADataSource is used instead of a specific
* driver implementation such as com.ibm.db2.jcc.DB2XADataSource.
*/
xaDS1 = (javax.sql.XADataSource)context.lookup("checkingAccounts");
xaDS2 = (javax.sql.XADataSource)context.lookup("savingsAccounts");
// The XADatasource contains the user ID and password.
// Get the XAConnection object from each XADataSource
xaconn1 = xaDS1.getXAConnection();
xaconn2 = xaDS2.getXAConnection();
// Get the java.sql.Connection object from each XAConnection
conn1 = xaconn1.getConnection();
conn2 = xaconn2.getConnection();
// Get the XAResource object from each XAConnection
xares1 = xaconn1.getXAResource();
xares2 = xaconn2.getXAResource();
// Create the Xid object for this distributed transaction.
// This example uses the com.ibm.db2.jcc.DB2Xid implementation
// of the Xid interface. This Xid can be used with any JDBC driver
// that supports JTA.
javax.transaction.xa.Xid xid1 =
new com.ibm.db2.jcc.DB2Xid(100, gtrid, bqual);
// Start the distributed transaction on the two connections.
// The two connections do NOT need to be started and ended together.
// They might be done in different threads, along with their SQL operations.
xares1.start(xid1, javax.transaction.xa.XAResource.TMNOFLAGS);
xares2.start(xid1, javax.transaction.xa.XAResource.TMNOFLAGS);
…
// Do the SQL operations on connection 1.
// Do the SQL operations on connection 2.
…
// Now end the distributed transaction on the two connections.
xares1.end(xid1, javax.transaction.xa.XAResource.TMSUCCESS);
xares2.end(xid1, javax.transaction.xa.XAResource.TMSUCCESS);
// If connection 2 work had been done in another thread,
// a thread.join() call would be needed here to wait until the
// connection 2 work is done.
try
{ // Now prepare both branches of the distributed transaction.
// Both branches must prepare successfully before changes
// can be committed.
// If the distributed transaction fails, an XAException is thrown.
rc1 = xares1.prepare(xid1);
if(rc1 == javax.transaction.xa.XAResource.XA_OK)
{ // Prepare was successful. Prepare the second connection.
rc2 = xares2.prepare(xid1);
if(rc2 == javax.transaction.xa.XAResource.XA_OK)
{ // Both connections prepared successfully and neither was read-only.
xares1.commit(xid1, false);
xares2.commit(xid1, false);
}
else if(rc2 == javax.transaction.xa.XAException.XA_RDONLY)
{ // The second connection is read-only, so just commit the
// first connection.
xares1.commit(xid1, false);
}
}
else if(rc1 == javax.transaction.xa.XAException.XA_RDONLY)
{ // SQL for the first connection is read-only (such as a SELECT).
// The prepare committed it. Prepare the second connection.
rc2 = xares2.prepare(xid1);
if(rc2 == javax.transaction.xa.XAResource.XA_OK)
{ // The first connection is read-only but the second is not.
// Commit the second connection.
xares2.commit(xid1, false);
}
else if(rc2 == javax.transaction.xa.XAException.XA_RDONLY)
{ // Both connections are read-only, and both already committed,
// so there is nothing more to do.
}
}
} catch (javax.transaction.xa.XAException xae)
{ // Distributed transaction failed, so roll it back.
// Report XAException on prepare/commit.
System.out.println("Distributed transaction prepare/commit failed. " +
"Rolling it back.");
System.out.println("XAException error code = " + xae.errorCode);
System.out.println("XAException message = " + xae.getMessage());
xae.printStackTrace();
try
{
xares1.rollback(xid1);
}
catch (javax.transaction.xa.XAException xae1)
{ // Report failure of rollback.
System.out.println("distributed Transaction rollback xares1 failed");
System.out.println("XAException error code = " + xae1.errorCode);
System.out.println("XAException message = " + xae1.getMessage());
}
try
{
xares2.rollback(xid1);
}
catch (javax.transaction.xa.XAException xae2)
{ // Report failure of rollback.
System.out.println("distributed Transaction rollback xares2 failed");
System.out.println("XAException error code = " + xae2.errorCode);
System.out.println("XAException message = " + xae2.getMessage());
}
}
try
{
conn1.close();
xaconn1.close();
}
catch (Exception e)
{
System.out.println("Failed to close connection 1: " + e.toString());
e.printStackTrace();
}
try
{
conn2.close();
xaconn2.close();
}
catch (Exception e)
{
System.out.println("Failed to close connection 2: " + e.toString());
e.printStackTrace();
}
}
catch (java.sql.SQLException sqe)
{
System.out.println("SQLException caught: " + sqe.getMessage());
sqe.printStackTrace();
}
catch (javax.transaction.xa.XAException xae)
{
System.out.println("XA error is " + xae.getMessage());
xae.printStackTrace();
}
catch (javax.naming.NamingException nme)
{
System.out.println(" Naming Exception: " + nme.getMessage());
}
}
}
建议:为了获得更好的性能,请先完成一个分布式事务,然后再启动另一个分布式或本地事务。
以上就是动力节点小编介绍的"使用JTA方法的分布式事务示例",希望对大家有帮助,想了解更多可查看Java分布式应用教程。动力节点在线学习教程,针对没有任何Java基础的读者学习,让你从入门到精通,主要介绍了一些Java基础的核心知识,让同学们更好更方便的学习和了解Java编程,感兴趣的同学可以关注一下。
Java实验班
0基础 0学费 15天面授
Java就业班
有基础 直达就业
Java夜校直播班
业余时间 高薪转行
Java在职加薪班
工作1~3年,加薪神器
Java架构师班
工作3~5年,晋升架构
提交申请后,顾问老师会电话与您沟通安排学习