程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 關於Weblogic中XAER_NOTA XAException的兩種解釋

關於Weblogic中XAER_NOTA XAException的兩種解釋

編輯:關於JAVA

某些時候,在weblogic執行XA操作的時候,我們會碰到如下的錯誤:

java.sql.SQLException: Unexpected exception while enlisting XAConnection java.sql.SQLException: XA error: XAER_NOTA : The XID is not valid start() failed on resource 'weblogic.jdbc.jta.DataSource': XAER_NOTA : The XID is not valid 

XAER_NOTA說明transaction branch在ResourceManager端(DB,MQ等)不存在。不存在通常由兩種可能:transaction branch被timeout掉了,另外一種情況就是這個branch壓根就沒有在ResourceManager端發起過。

這篇文章主要針對2做一下說明,對於1,我們可以在Weblogic的XAConnectionPool設定中Enable XA Transaction Timeout,並對此設定一個合理的值,建議這個值比global transaction timeout大。這樣weblogic在調用xaStart()的時候,會通知RM,該branch的timeout時間,而不是使用RM自己默認的timeout(對於Oracle,默認為60秒,但一般會在120秒的時候,tx branch才會被Oracle timeout掉)。

對於2, 一般會跟配置有關系,比如兩個XA datasource指向同一個XAConnectionPool,或多個XAConnectionPool指向同一個Database,我們以多個datasource指向同一connection為例:

1:假如我們有如下的配置環境:

XADatasource_11---->XAPool_A---->Databse_A

XADatasource_21---->XAPool_B---->Databse_B

這樣的配置環境中,我們做XA相關的操作是沒有問題的。

1         public void xaTest()
2       {
3            try{
4                UserTransaction tx = getUserTransaction();
5                tx.setTransactionTimeout(1000);
6                tx.begin();
7                Connection conn1 = getConnection("t3://localhost:7011",XADatasource_11);
8                Connection conn2 = getConnection("t3://localhost:7021",XADatasource_21);
9                this.executeInsertInPSMT(conn1,null);
10                this.executeAnoInsertInPSMT(conn2,null);
11                conn1.close();
12                conn2.close();
13                tx.commit();
14            }catch(Exception e){}
15       }

2:如果基於業務需要,我們需要額外配置兩個XA Datasource,分別指向 XAPool_A、XAPool_B,如下:

XADatasource_12----〉XAPool_A

XADatasource_22----〉XAPool_B

部署Datasource的時候,Weblogic會判斷這個Datasource是不是XA類型的,如果是XA類型的Datasource,我們需要將這個datasource實例注冊到Process- wide的resourceDescriptorList中,如下:

registerResource(poolName,(XAResource)driverInstance,registrationProperties);

在register前,我們先調用unregisterResource(poolName)將該poolName 對應的resource從 resourceDescriptorList中unregister掉。這樣 XADatasource_12、XADatasource_22部署後,我們可以看到process-wide的 resourceDescriptorList中的對象變化:

部署前:XADatasource_11, XADatasource_21

部署後:XADatasource_12, XADatasource_22

注意:如果XADatasource11、12, XADatasource_21、22不存在多數據源 指向同連接池的話,部署後,四個Datasource應該都出現在 resourceDescriptorList中。

3:如果我們此時執行xaTest()測試代碼,過程如下:

3.1:Connection conn1 = getConnection("t3://localhost:7011",XADatasource_11);

在getConnection()的時候, weblogic中需要將 XAResource enlist到當前的transaction中,如下:

Thread [ExecuteThread: '14' for queue: 'weblogic.kernel.Default'] (Suspended)
ServerTransactionImpl.enlistResource(XAResource) line: 412
DataSource.enlist(Transaction) line: 1519
DataSource.refreshXAConnAndEnlist(XAConnection,JTAConnection,boolean) line: 1459
DataSource.getConnection() line: 452
DataSource.connect(String,Properties) line: 410
RmiDataSource.getConnection() line: 329
RmiDataSource_WLSkel.invoke(int,InboundRequest,OutboundResponse,Object) line: not available
ClusterableServerRef(BasicServerRef).invoke(RuntimeMethodDescriptor,InboundRequest,OutboundResponse) line: 492
ClusterableServerRef(ReplicaAwareServerRef).invoke(RuntimeMethodDescriptor,InboundRequest,OutboundResponse) line: 108
BasicServerRef$1.run() line: 435
AuthenticatedSubject.doAs(AbstractSubject,PrivilegedExceptionAction) line:363
SecurityManager.runAs(AuthenticatedSubject,AuthenticatedSubject,PrivilegedExceptionAction) line: 147
ClusterableServerRef(BasicServerRef).handleRequest(InboundRequest) line: 430
BasicExecuteRequest.execute(ExecuteThread) line: 35
ExecuteThread.execute(ExecuteRequest) line: 224
ExecuteThread.run() line: 183

3.1.1: 在enlistResource()中,我們首先檢查 XADatasource_11實例對應的resourceDescriptor在process- wide的 resourceDesriptorList中是否存在(很顯然,它是不存在的,因為我們在部署 XADatasource_12的時候,它被 unregister掉了)。接下來,我們會檢查 XADatasource_11實例對應的resourceInfo在transaction-wide 的 resourceInfoList中是否存在(因為這個transaction剛剛開始, resourceInfoList中沒有任何 resource)。因為XADatasource_11實例對應的 resourceInfo在resourceInfoList中不存在,我們需要創建一個 XAServerResourceInfo來和XADatasource_11實例關聯。如下:

ri = new XAServerResourceInfo(xar)

3.1.2: 在XAServerResourceInfo初始化中,我們會再次檢查和XADatasource_11實例對應的resourceDescriptor 是否在 resourceDescriptorList中存在(同樣,它依然是不存的)。因為 resourceDescriptor在 resourceDescriptorList中不存在,我們會從xaResource 獲取xarName ,如下:

String xarName = aXar.getClass().getName(); //weblogic.jdbc.jta.DataSource

然後根據xarName 去resourceDescriptorList中繼續檢 查,是否存在該xarName 對應的resourceDesriptor。因為此時 resourceDescriptorList中對象如下:

By instance: XADatasource_12, XADatasource_22

By name: XAPool_A,XAPool_B

3.1.3: 所以無論是根據XADatasource_11實例,還是根據 weblogic.jdbc.jta.DataSource都不能從resourceDescriptorList中找到與其對應 的 resourceDescriptor。這是我們會根據xarName (weblogic.jdbc.jta.DataSource)創建一個 resourceDescriptor,如下:

rd = (XAResourceDescriptor) create(xarName,aXar,DYNAMIC);

3.1.4: XAResourceDescriptor創建完成後,我們會將該 resourceDescriptor放入 resourceDescriptorList中,此時 resourceDescritporList中對象如下:

By instance: XADatasource_12, XADatasource_22,XADatasource_11

By name: XAPool_A,XAPool_B,weblogic,jdbc.jta.DataSource

這是返回到3.1.2的XAServerResourceInfo初始化中,我們將該resourceInfo的xaResource設定為傳入的參數 xar,resourceInfo的 name被設定為3.1.3中的xarName,即weblogic.jdba.jta.DataSource.

3.1.5:回到3.1.1, XAServerResourceInfo實例創建後,我們根據resourceInfo的name,來檢查當前tx的resourceInfoList 是否存在對應的resourceInfo,對於一個剛剛開始的transaction,此時它的resourceInfoList 是空的。如果同名的 resourceInfo被detect到,我們會將該resourceInfo的 enlistElseWhere置為true(即已被enlist)。因為我們新創建的resourceInfo之前沒有被enlist過,所以我們需要調用resourceInfo的enlist()來將 XADatasource_11 enlist到當前tx中。此時當前transaction的resourceInfoList 對象如下:

By instance: XADatasource_11

By name: weblogic.jdbc.jta.Datasource

3.1.6: 在resourceInfo的enlist中,如果resourceInfo的 enlistElseWhere為true,將要傳遞給xaStart的flag為TMNOFLAGS, 否則為 TMJOIN。然後獲取調用

Xid bXid = getXIDwithBranch((XidImpl)tx.getXID())

獲取事務分支ID,最後綜合BRANCH_ID,FLAGS 來通知RESOURCE_MANAGER(DataBase_A)啟動一個事務。

注意:TMNOFLAGS是通知RESOURCE_MANAGER啟動 一個新事務

TMJOIN是將當前線程和BRANCH_ID 對應的事務關聯。

3.2:Connection conn1 = getConnection("t3://localhost:7011",XADatasource_11);

3.1中的動作會被重復,但中間的差別如下:

3.2.1:XADatasource_21實例對應resourceDescriptor同樣不會在resourceDescriptorList中被發現,因為它已經在register XADatasource_22的時候被unregister掉了。XADatasource_21對應的resourceInfo不存於當前 transaction的resourceInfoList中,resourceInfoList中只有XADatasource_11實例對應的一個名叫weblogic.jdbc.jta.DataSource的對象,它在3.1.5中被置入。 同3.1.1,我們這時候需要根據 XADatasource_21, 創建一個與其對應的 resourceInfo,如下:

ri = new XAServerResourceInfo(xar)

3.2.2:創建XAServerResourceInfo的時候,因為此時 resourceDescriptorList中對象如下(參考 3.1.4):

By instance: XADatasource_12, XADatasource_22, XADatasource_11

By name: XAPool_A,XAPool_B,weblogic,jdbc.jta.DataSource

根據XADatasource_21我們找不到這個resourceDescriptor,但我們能根據xarName,即weblogic.jdbc.jta.Datasource找到一個 resourceDescriptor。因此我們不會去創建一個新的 resourceDescriptor,而使用這個已存在的resourceDescriptor,並用它的名字作為該resourceInfo的名字,即新創建的resourceInfo名為:weblogic.jdbc.jta.DataSource。因此3.1.3,3.1.4步驟不會被執行。

3.2.5:XAServerResourceInfo被創建後,我們會根據 resouceInfo的名字,即 weblogic.jdbc.jta.DataSource,檢查當前tx的 resourceInfoList中是否存在對應的resourceInfo。因為3.1.5結束的時候,我們 已經將一個名為 weblogic.jdbc.jta.DataSource的resourceInfo置入當前tx的 resourceInfoList中,所以這裡我們能夠找到一個與 weblogic.jdbc.jta.DataSource對應的resourceInfo。因此我們會將這個新創建的 resourceInfo的enlistElseWhere置為true。

3.2.6:因為resourceInfo的enlistElseWhere為true,所以我們要傳遞給xaStart的flag為TMJOIN(實際需要的應該是TMNOFALGS),接下來會調用 start(xid,TMJOIN)來通知RESOURCE_MANAGER(Database_B)將當前線程和已有的 transaction branch關聯。但Database_B中沒有和該global transaction相對應的 transaction branch,所以TMJOIN失敗,即如下的錯誤會被拋出,

java.sql.SQLException: Unexpected exception while enlisting XAConnection java.sql.SQLException: XA error: XAER_NOTA : The XID is not valid start() failed on resource 'weblogic.jdbc.jta.DataSource': XAER_NOTA : The XID is not valid

這個問題是weblogic的產品限制,它是WAD(work as design)的,並不是產品bug。在weblogic81sp6中,這種配置會有錯誤信息輸出。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved