某些时候,在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中,这种配置会有错误信息输出。
posted on 2009-01-12 20:48
走走停停又三年 阅读(3166)
评论(0) 编辑 收藏 所属分类:
Weblogic