posts - 42,comments - 83,trackbacks - 0

        某些时候,在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

只有注册用户登录后才能发表评论。


网站导航: