最近這幾天一直在整 怎麼實現分佈式事務。找了很多資料,不過大都相近類同。對Oracle、SQL Server、Mysql數已做過測試,其中Mysql5.0以上的才支持分佈式事務。
對於這些,主要是之前根本沒有接觸過分佈式事務,還錯找了一些分佈式事數據庫的資料,呵呵,結果不是我目前所需要的。
測試過程中出現了很多錯誤,一直都通不過,以爲是用戶權限還有數據庫服務的問題,但一切都配置良好的情況下還一直都通不過。結果發現,我導入的都是一些普通的JDBC連接包,於是狂搜實現XA事務的jar包。
Mysql: mysql-connector-java-5.1.6-bin.jar
SQL Server: sqljdbc.jar
Oracle: ojdbc14.jar
用的是這些包才順利通過運行。後面會附上這幾個jar包。
好了,把源代碼也附上:
import com.microsoft.sqlserver.jdbc.SQLServerXADataSource;
import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;
import java.sql.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.sql.*;
import javax.transaction.xa.*;
import oracle.jdbc.xa.client.OracleXADataSource;
public class Mutil_DataSource_Test {
public static void main(String[] args){
Mutil_DataSource_Test mdt = new Mutil_DataSource_Test();
try {
mdt.test1();
} catch (Exception ex) {
System.out.println("除SQLException、XAException之外的異常: \n");
Logger.getLogger(Mutil_DataSource_Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
class MyXid implements Xid{
int formatId;
byte globalTransactionId[];
byte branchQualifier[];
public MyXid(){
}
public MyXid(int formatId,byte[] globalTransactionId,byte[] branchQualifier){
this.formatId = formatId;
this.globalTransactionId = globalTransactionId;
this.branchQualifier = branchQualifier;
}
public int getFormatId() {
return this.formatId;
}
public void setFormatId(int formatId){
this.formatId = formatId;
}
public byte[] getGlobalTransactionId() {
return this.globalTransactionId;
}
public void setGlobalTransactionId(byte[] globalTransactionId){
this.globalTransactionId = globalTransactionId;
}
public byte[] getBranchQualifier() {
return this.branchQualifier;
}
public void setBranchQualifier(byte[] branchQualifier){
this.branchQualifier = branchQualifier;
}
}
//多數據庫測試
public void test1() {
//定義所需用到的變量
Connection mysqlCn = null;
Connection sqlCn = null;
Connection mysqlCn2 = null;
Connection oraCn = null;
MysqlXADataSource mysqlDs = null;
SQLServerXADataSource sqlDs = null;
MysqlXADataSource mysqlDs2 = null;
OracleXADataSource oraDs = null;
XAConnection xamysqlCn = null;
XAConnection xasqlCn = null;
XAConnection xamysqlCn2 = null;
XAConnection xaoraCn = null;
XAResource xamysqlRes = null;
XAResource xasqlRes = null;
XAResource xamysqlRes2 = null;
XAResource xaoraRes = null;
Xid mysqlXid = null;
Xid sqlXid = null;
Xid mysqlXid2 = null;
Xid oraXid = null;
Statement mysqlpst = null;
Statement sqlpst = null;
Statement mysqlpst2 = null;
Statement orapst = null;
try{
//獲得數據源
mysqlDs = new MysqlXADataSource();
mysqlDs.setURL("jdbc:mysql://localhost:3306/test");
mysqlDs2 = new MysqlXADataSource();
mysqlDs2.setURL("jdbc:mysql://10.10.10.119:3306/test");
sqlDs = new SQLServerXADataSource();
sqlDs.setURL("jdbc:sqlserver://10.10.10.119:1433;DatabaseName=RTC;loginTimeout=20;user=sa;password=chgpwd122105");
// sqlDs.setUser("sa");
// sqlDs.setPassword("chgpwd122105");
// sqlDs.setServerName("10.10.10.119");
// sqlDs.setPortNumber(1433);
// sqlDs.setDatabaseName("RTC");
oraDs = new OracleXADataSource();
oraDs.setURL("jdbc:oracle:thin:@10.10.10.119:1521:WMS");
//獲得連接
xamysqlCn = mysqlDs.getXAConnection("root", "9999");
System.out.println("xamysqlCn: "+xamysqlCn);
xasqlCn = sqlDs.getXAConnection();
System.out.println("xasqlCn: "+xasqlCn);
xamysqlCn2 = mysqlDs2.getXAConnection("root", "9999");
System.out.println("xamysqlCn2: "+xamysqlCn2);
xaoraCn = oraDs.getXAConnection("tiger", "tiger");
System.out.println("xaoraCn: "+xaoraCn);
mysqlCn = xamysqlCn.getConnection();
sqlCn = xasqlCn.getConnection();
mysqlCn2 = xamysqlCn2.getConnection();
oraCn = xaoraCn.getConnection();
mysqlpst = mysqlCn.createStatement();
sqlpst = sqlCn.createStatement();
mysqlpst2 = mysqlCn2.createStatement();
orapst = oraCn.createStatement();
//定義XAResource
xamysqlRes = xamysqlCn.getXAResource();
xasqlRes = xasqlCn.getXAResource();
xamysqlRes2 = xamysqlCn2.getXAResource();
xaoraRes = xaoraCn.getXAResource();
//定義Xid
mysqlXid = new MyXid(0, new byte[]{0x01}, new byte[]{0x02});
sqlXid = new MyXid(0, new byte[]{0x01}, new byte[]{0x03});
mysqlXid2 = new MyXid(0, new byte[]{0x01}, new byte[]{0x04});
oraXid = new MyXid(0, new byte[]{0x01}, new byte[]{0x05});
//執行Mysql
xamysqlRes.start(mysqlXid, XAResource.TMNOFLAGS);
mysqlpst.executeUpdate("insert into test values(4,'XA','F','Class4')");
xamysqlRes.end(mysqlXid, XAResource.TMSUCCESS);
//執行SQLServer
xasqlRes.start(sqlXid, XAResource.TMNOFLAGS);
sqlpst.executeUpdate("insert into test values('444')");
xasqlRes.end(sqlXid, XAResource.TMSUCCESS);
//執行Mysql
xamysqlRes2.start(mysqlXid2, XAResource.TMNOFLAGS);
mysqlpst2.executeUpdate("insert into test values(4,'XA','F','Class4')");
xamysqlRes2.end(mysqlXid2, XAResource.TMSUCCESS);
//執行Oracle
System.out.println("xaoraRes: "+xaoraRes);
xaoraRes.start(oraXid, XAResource.TMNOFLAGS);
orapst.executeUpdate("insert into test123 values('4','44','444')");
System.out.println("oraXid: "+oraXid);
xaoraRes.end(oraXid, XAResource.TMSUCCESS);
//準備
int mysqlRea = xamysqlRes.prepare(mysqlXid);
int sqlRea = xasqlRes.prepare(sqlXid);
int mysqlRea2 = xamysqlRes2.prepare(mysqlXid2);
int oraRea = xaoraRes.prepare(oraXid);
//判斷準備就緒與否 提交或回滾
if(mysqlRea == xamysqlRes.XA_OK && mysqlRea2 == xamysqlRes.XA_OK && oraRea == xaoraRes.XA_OK && sqlRea == xasqlRes.XA_OK){
// if(mysqlRea == xamysqlRes.XA_OK && mysqlRea2 == xamysqlRes.XA_OK && oraRea == xaoraRes.XA_OK){
// if(mysqlRea == xamysqlRes.XA_OK && sqlRea == xasqlRes.XA_OK && mysqlRea2 == xamysqlRes.XA_OK){
// if(mysqlRea == xamysqlRes.XA_OK && mysqlRea2 == xamysqlRes.XA_OK){
xamysqlRes.commit(mysqlXid, false);
System.out.println("Mysql 事務提交成功!");
xasqlRes.commit(sqlXid, false);
System.out.println("SQLServer 事務提交成功!");
xamysqlRes2.commit(mysqlXid2, false);
System.out.println("Mysql2 事務提交成功!");
xaoraRes.commit(oraXid, false);
System.out.println("Oracle 事務提交成功!");
}else{
xamysqlRes.rollback(mysqlXid);
xasqlRes.rollback(sqlXid);
xamysqlRes2.rollback(mysqlXid2);
xaoraRes.rollback(oraXid);
System.out.println("事務回滾成功!");
}
}catch(SQLException ex){
Logger.getLogger(Mutil_DataSource_Test.class.getName()).log(Level.SEVERE, null, ex);
try{
xamysqlRes.rollback(mysqlXid);
xasqlRes.rollback(sqlXid);
xamysqlRes2.rollback(mysqlXid2);
xaoraRes.rollback(oraXid);
}catch(XAException e){
System.out.println("回滾也出錯咯!~");
e.printStackTrace();
}
}catch(XAException ex){
Logger.getLogger(Mutil_DataSource_Test.class.getName()).log(Level.SEVERE, null, ex);
}finally{
try {
//關閉
mysqlpst.close();
mysqlCn.close();
xamysqlCn.close();
sqlpst.close();
sqlCn.close();
xasqlCn.close();
mysqlpst2.close();
mysqlCn2.close();
xamysqlCn2.close();
orapst.close();
oraCn.close();
xaoraCn.close();
} catch (SQLException ex) {
Logger.getLogger(Mutil_DataSource_Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
分佈式事務分爲兩個階段,第一個階段相當於是一個預提交,第二階段纔是正真的提交。
首先要實現的是Xid接口,formatId可以理解爲一個全局事務的ID,不過我上面的代碼沒有去做一些異常的處理,還有正確的鏈接的關閉,只是自己做的一個小小的測試,以後項目中再去處理這些。第一階段如果出錯或是不順利則不會提交,需要做一些回滾處理。如果順利則準備提交,進入第二階段,在第二階段可能會出現問題,如果第一個分支事務提交成功了,而後有一個分支事務提交失敗,這樣則會造成數據不準確,目前還不知道有沒有方法可以解決些問題,好像XAResource.recover()可以處理,但具體怎麼解決,在項目中自己還是可以想到辦法解決。
對XA分佈式事務 我是初學者,而且也沒有誰指點,只是在網上找些資料。我上面的理解可能也還有些不足或是錯誤。希望高手看到後能指點指點。
對於這些,主要是之前根本沒有接觸過分佈式事務,還錯找了一些分佈式事數據庫的資料,呵呵,結果不是我目前所需要的。
測試過程中出現了很多錯誤,一直都通不過,以爲是用戶權限還有數據庫服務的問題,但一切都配置良好的情況下還一直都通不過。結果發現,我導入的都是一些普通的JDBC連接包,於是狂搜實現XA事務的jar包。
Mysql: mysql-connector-java-5.1.6-bin.jar
SQL Server: sqljdbc.jar
Oracle: ojdbc14.jar
用的是這些包才順利通過運行。後面會附上這幾個jar包。
好了,把源代碼也附上:
import com.microsoft.sqlserver.jdbc.SQLServerXADataSource;
import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;
import java.sql.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.sql.*;
import javax.transaction.xa.*;
import oracle.jdbc.xa.client.OracleXADataSource;
public class Mutil_DataSource_Test {
public static void main(String[] args){
Mutil_DataSource_Test mdt = new Mutil_DataSource_Test();
try {
mdt.test1();
} catch (Exception ex) {
System.out.println("除SQLException、XAException之外的異常: \n");
Logger.getLogger(Mutil_DataSource_Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
class MyXid implements Xid{
int formatId;
byte globalTransactionId[];
byte branchQualifier[];
public MyXid(){
}
public MyXid(int formatId,byte[] globalTransactionId,byte[] branchQualifier){
this.formatId = formatId;
this.globalTransactionId = globalTransactionId;
this.branchQualifier = branchQualifier;
}
public int getFormatId() {
return this.formatId;
}
public void setFormatId(int formatId){
this.formatId = formatId;
}
public byte[] getGlobalTransactionId() {
return this.globalTransactionId;
}
public void setGlobalTransactionId(byte[] globalTransactionId){
this.globalTransactionId = globalTransactionId;
}
public byte[] getBranchQualifier() {
return this.branchQualifier;
}
public void setBranchQualifier(byte[] branchQualifier){
this.branchQualifier = branchQualifier;
}
}
//多數據庫測試
public void test1() {
//定義所需用到的變量
Connection mysqlCn = null;
Connection sqlCn = null;
Connection mysqlCn2 = null;
Connection oraCn = null;
MysqlXADataSource mysqlDs = null;
SQLServerXADataSource sqlDs = null;
MysqlXADataSource mysqlDs2 = null;
OracleXADataSource oraDs = null;
XAConnection xamysqlCn = null;
XAConnection xasqlCn = null;
XAConnection xamysqlCn2 = null;
XAConnection xaoraCn = null;
XAResource xamysqlRes = null;
XAResource xasqlRes = null;
XAResource xamysqlRes2 = null;
XAResource xaoraRes = null;
Xid mysqlXid = null;
Xid sqlXid = null;
Xid mysqlXid2 = null;
Xid oraXid = null;
Statement mysqlpst = null;
Statement sqlpst = null;
Statement mysqlpst2 = null;
Statement orapst = null;
try{
//獲得數據源
mysqlDs = new MysqlXADataSource();
mysqlDs.setURL("jdbc:mysql://localhost:3306/test");
mysqlDs2 = new MysqlXADataSource();
mysqlDs2.setURL("jdbc:mysql://10.10.10.119:3306/test");
sqlDs = new SQLServerXADataSource();
sqlDs.setURL("jdbc:sqlserver://10.10.10.119:1433;DatabaseName=RTC;loginTimeout=20;user=sa;password=chgpwd122105");
// sqlDs.setUser("sa");
// sqlDs.setPassword("chgpwd122105");
// sqlDs.setServerName("10.10.10.119");
// sqlDs.setPortNumber(1433);
// sqlDs.setDatabaseName("RTC");
oraDs = new OracleXADataSource();
oraDs.setURL("jdbc:oracle:thin:@10.10.10.119:1521:WMS");
//獲得連接
xamysqlCn = mysqlDs.getXAConnection("root", "9999");
System.out.println("xamysqlCn: "+xamysqlCn);
xasqlCn = sqlDs.getXAConnection();
System.out.println("xasqlCn: "+xasqlCn);
xamysqlCn2 = mysqlDs2.getXAConnection("root", "9999");
System.out.println("xamysqlCn2: "+xamysqlCn2);
xaoraCn = oraDs.getXAConnection("tiger", "tiger");
System.out.println("xaoraCn: "+xaoraCn);
mysqlCn = xamysqlCn.getConnection();
sqlCn = xasqlCn.getConnection();
mysqlCn2 = xamysqlCn2.getConnection();
oraCn = xaoraCn.getConnection();
mysqlpst = mysqlCn.createStatement();
sqlpst = sqlCn.createStatement();
mysqlpst2 = mysqlCn2.createStatement();
orapst = oraCn.createStatement();
//定義XAResource
xamysqlRes = xamysqlCn.getXAResource();
xasqlRes = xasqlCn.getXAResource();
xamysqlRes2 = xamysqlCn2.getXAResource();
xaoraRes = xaoraCn.getXAResource();
//定義Xid
mysqlXid = new MyXid(0, new byte[]{0x01}, new byte[]{0x02});
sqlXid = new MyXid(0, new byte[]{0x01}, new byte[]{0x03});
mysqlXid2 = new MyXid(0, new byte[]{0x01}, new byte[]{0x04});
oraXid = new MyXid(0, new byte[]{0x01}, new byte[]{0x05});
//執行Mysql
xamysqlRes.start(mysqlXid, XAResource.TMNOFLAGS);
mysqlpst.executeUpdate("insert into test values(4,'XA','F','Class4')");
xamysqlRes.end(mysqlXid, XAResource.TMSUCCESS);
//執行SQLServer
xasqlRes.start(sqlXid, XAResource.TMNOFLAGS);
sqlpst.executeUpdate("insert into test values('444')");
xasqlRes.end(sqlXid, XAResource.TMSUCCESS);
//執行Mysql
xamysqlRes2.start(mysqlXid2, XAResource.TMNOFLAGS);
mysqlpst2.executeUpdate("insert into test values(4,'XA','F','Class4')");
xamysqlRes2.end(mysqlXid2, XAResource.TMSUCCESS);
//執行Oracle
System.out.println("xaoraRes: "+xaoraRes);
xaoraRes.start(oraXid, XAResource.TMNOFLAGS);
orapst.executeUpdate("insert into test123 values('4','44','444')");
System.out.println("oraXid: "+oraXid);
xaoraRes.end(oraXid, XAResource.TMSUCCESS);
//準備
int mysqlRea = xamysqlRes.prepare(mysqlXid);
int sqlRea = xasqlRes.prepare(sqlXid);
int mysqlRea2 = xamysqlRes2.prepare(mysqlXid2);
int oraRea = xaoraRes.prepare(oraXid);
//判斷準備就緒與否 提交或回滾
if(mysqlRea == xamysqlRes.XA_OK && mysqlRea2 == xamysqlRes.XA_OK && oraRea == xaoraRes.XA_OK && sqlRea == xasqlRes.XA_OK){
// if(mysqlRea == xamysqlRes.XA_OK && mysqlRea2 == xamysqlRes.XA_OK && oraRea == xaoraRes.XA_OK){
// if(mysqlRea == xamysqlRes.XA_OK && sqlRea == xasqlRes.XA_OK && mysqlRea2 == xamysqlRes.XA_OK){
// if(mysqlRea == xamysqlRes.XA_OK && mysqlRea2 == xamysqlRes.XA_OK){
xamysqlRes.commit(mysqlXid, false);
System.out.println("Mysql 事務提交成功!");
xasqlRes.commit(sqlXid, false);
System.out.println("SQLServer 事務提交成功!");
xamysqlRes2.commit(mysqlXid2, false);
System.out.println("Mysql2 事務提交成功!");
xaoraRes.commit(oraXid, false);
System.out.println("Oracle 事務提交成功!");
}else{
xamysqlRes.rollback(mysqlXid);
xasqlRes.rollback(sqlXid);
xamysqlRes2.rollback(mysqlXid2);
xaoraRes.rollback(oraXid);
System.out.println("事務回滾成功!");
}
}catch(SQLException ex){
Logger.getLogger(Mutil_DataSource_Test.class.getName()).log(Level.SEVERE, null, ex);
try{
xamysqlRes.rollback(mysqlXid);
xasqlRes.rollback(sqlXid);
xamysqlRes2.rollback(mysqlXid2);
xaoraRes.rollback(oraXid);
}catch(XAException e){
System.out.println("回滾也出錯咯!~");
e.printStackTrace();
}
}catch(XAException ex){
Logger.getLogger(Mutil_DataSource_Test.class.getName()).log(Level.SEVERE, null, ex);
}finally{
try {
//關閉
mysqlpst.close();
mysqlCn.close();
xamysqlCn.close();
sqlpst.close();
sqlCn.close();
xasqlCn.close();
mysqlpst2.close();
mysqlCn2.close();
xamysqlCn2.close();
orapst.close();
oraCn.close();
xaoraCn.close();
} catch (SQLException ex) {
Logger.getLogger(Mutil_DataSource_Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
分佈式事務分爲兩個階段,第一個階段相當於是一個預提交,第二階段纔是正真的提交。
首先要實現的是Xid接口,formatId可以理解爲一個全局事務的ID,不過我上面的代碼沒有去做一些異常的處理,還有正確的鏈接的關閉,只是自己做的一個小小的測試,以後項目中再去處理這些。第一階段如果出錯或是不順利則不會提交,需要做一些回滾處理。如果順利則準備提交,進入第二階段,在第二階段可能會出現問題,如果第一個分支事務提交成功了,而後有一個分支事務提交失敗,這樣則會造成數據不準確,目前還不知道有沒有方法可以解決些問題,好像XAResource.recover()可以處理,但具體怎麼解決,在項目中自己還是可以想到辦法解決。
對XA分佈式事務 我是初學者,而且也沒有誰指點,只是在網上找些資料。我上面的理解可能也還有些不足或是錯誤。希望高手看到後能指點指點。