控制两阶段提交事务的提交顺序

时间:2018-03-07 05:18:38

标签: websphere websphere-8 distributed-transactions xa

我们在Webshere Application Server 8.5.5上运行了一个Java应用程序。有两个进程在单独的JVM中运行。 该应用程序正在使用IBM Webshere Queue Manager和Oracle 11c数据库进行一些集成。 JMS和JDBC资源都配置为使用XA事务。

流程1:

  1. MESSAGES 队列中读取消息,并提取用于标识相关消息的消息密钥
  2. 将消息保存到数据库。
  3. 检查 KEYS 表中是否存在消息键,以及是否未插入消息键
  4. 仅在上面插入时才会将消息密钥放入 KEYS 队列
  5. 提交交易
  6. 流程2:

    1. KEYS 队列
    2. 获取消息密钥
    3. KEYS
    4. 中删除消息密钥
    5. 处理与 MESSAGES
    6. 中收到的消息密钥关联的所有消息

      我们观察到,在从 KEYS 队列中获取消息密钥后,大约5%的案例中 PROCESS 2 有时无法找到要从中删除的记录 KEYS 表只是在几毫秒后可用。试图多次删除它修复了问题,但很明显即使 PROCESS 1 启用了XA,它首先提交JMS资源,然后JDBC在很短的时间内将数据带入不一致的状态。

      所以这是我的问题:

      有没有办法强制事务管理器先提交JDBC然后再提交JMS?

      我们在IBM knowledge center上找到了这个,我们尝试像这样配置commit-priority:

      <?xml version="1.0" encoding="UTF-8"?>
      <ejb-jar-ext xmlns="http://websphere.ibm.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://websphere.ibm.com/xml/ns/javaee http://websphere.ibm.com/xml/ns/javaee/ibm-ejb-jar-ext_1_0.xsd"
               version="1.0">
          <session name="RepositoryInstanceFacade">
              <resource-ref name="jms/MQConnectionFactory" commit-priority="1" isolation-level="TRANSACTION_READ_COMMITTED"/>
              <resource-ref name="jdbc/MessageManagerDB" commit-priority="2" isolation-level="TRANSACTION_READ_COMMITTED"/>
          </session>
      </ejb-jar-ext>
      

      然而,这并没有解决我们的问题。我相信我们并不是唯一面临这个问题的人,但我只是不知道该怎么做才能尝试。最后我们将消息密钥放回 KEYS 队列中,这解决了问题,但它看起来像是一个非常非正统的工作,而不是一个关键的24 x 7应用程序的良好解决方案。 / p>

      提前感谢您的意见。

      更新 我在我的ejb应用程序的META-INF文件夹中添加了这个资源绑定文件ibm-ejb-jar-bnd.xml文件,但仍然没有运气。作为部署的一部分,我可以看到IBM操纵该文件并将其转换为XMI文件

      <?xml version="1.0" encoding="UTF-8"?>
      <ejb-jar-bnd
          xmlns="http://websphere.ibm.com/xml/ns/javaee"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://websphere.ibm.com/xml/ns/javaee
           http://websphere.ibm.com/xml/ns/javaee/ibm-ejb-jar-bnd_1_0.xsd" 
          version="1.0">
      
          <session name="RepositoryInstanceFacade">
              <resource-ref name="jdbc/MessageManagerDB" binding-name="jdbc/MessageManagerDB"/>
          </session>
      </ejb-jar-bnd>
      

      更新2 我最终在两个JVM中配置了以下配置,每个JVM运行自己的应用程序:

      application.xml:
      
      <?xml version="1.0" encoding="UTF-8"?>
      <application xmlns="http://java.sun.com/xml/ns/javaee"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_6.xsd"
                   version="6">
          ...      
          <resource-ref>
              <description>XA Message Manager Data Source</description>
              <res-ref-name>java:app/env/jdbc/MessageManagerDB</res-ref-name>
              <res-type>javax.sql.DataSource</res-type>
              <res-auth>Container</res-auth>
              <res-sharing-scope>Shareable</res-sharing-scope>
          </resource-ref>
      </application>
      
      
      
      ibm-aplication-bnd.xml:
      
          <?xml version="1.0" encoding="UTF-8"?>
      <application-bnd
              xmlns="http://websphere.ibm.com/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://websphere.ibm.com/xml/ns/javaee
               http://websphere.ibm.com/xml/ns/javaee/ibm-application-bnd_1_0.xsd"
              version="1.0">
      
          <resource-ref name="java:app/env/jdbc/MessageManagerDB" binding-name="jdbc/MessageManagerDB"/>
      </application-bnd>
      
      
      ibm-ejb-jar-ext.xml:
      
      <?xml version="1.0" encoding="UTF-8"?>
      <ejb-jar-ext xmlns="http://websphere.ibm.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://websphere.ibm.com/xml/ns/javaee http://websphere.ibm.com/xml/ns/javaee/ibm-ejb-jar-ext_1_0.xsd"
                   version="1.0">
          <session name="RepositoryInstanceFacade">
              <resource-ref name="java:app/env/jdbc/MessageManagerDB" isolation-level="TRANSACTION_READ_COMMITTED" commit-priority="2"/>
          </session>
      </ejb-jar-ext>
      
      spring data source bean:
      
       <jee:jndi-lookup id="messageManagerDB" jndi-name="java:app/env/jdbc/MessageManagerDB"/>
      

      再次运行我的测试。在测试运行期间我非常高兴,因为日志中没有警告消息。然而,测试运行了几个小时,很难手动检查。最后,仍然有三条警告消息显示在数据库插入可用之前仍然从队列中读取了JMS消息。我还缺少什么吗?

      请注意,我根据IBM文档将JMS连接工厂的任何设置都设置为零,因此它的提交优先级低于JDBC。

      更新3

      根据评论和IBM支持人员的建议,我最终得到以下设置:

      ejb-jar.xml:
      <session name="RepositoryInstanceFacade">
          ...
          <resource-ref>
              <description>XA Message Manager Data Source</description>
              <res-ref-name>jdbc/MessageManagerDB</res-ref-name>
              <res-type>javax.sql.DataSource</res-type>
              <res-auth>Container</res-auth>
              <res-sharing-scope>Shareable</res-sharing-scope>
          </resource-ref>
      </session>
      
      ibm-ejb-jar-bnd.xml:
      <resource-ref name="jdbc/MessageManagerDB" binding-name="jdbc/MessageManagerDB"/>
      
      ibm-ejb-jar-ext.xml:
      <session name="RepositoryInstanceFacade">
          <resource-ref name="jdbc/MessageManagerDB" isolation-level="TRANSACTION_READ_COMMITTED" commit-priority="2"/>
      </session>
      
      spring data source bean:
      <jee:jndi-lookup id="messageManagerDB" jndi-name="java:comp/env/jdbc/MessageManagerDB"/>
      

      有了这些设置,JMS仍然首先被提交,而JDBC最后被提交,所以它仍然没有按预期工作。

1 个答案:

答案 0 :(得分:0)

根据我在评论中提出的问题,资源引用实际上并未用于查找资源,这就是为什么commit-priority属性不被尊重的原因。在问题的UPDATE部分,您已经通过为JDBC资源添加资源引用绑定而更加接近(您还需要JMS资源的等效项)。您还需要在ejb-jar.xml部署描述符中定义资源引用(如果您愿意,还需要等效注释),然后从应用程序中查找资源,您需要使用命名空间作为资源引用,默认情况下是java:comp / env,因此您需要将资源查找为java:comp / env / jms / MQConnectionFactory和java:comp / env / jdbc / MessageManagerDB。如果您需要在组件级别之外的可见性,您可能需要在另一个范围内定义,例如java:module / env或java:app / env,这意味着将资源引用名称更新为相应的值。

更新:使用java:app name

的ejb部署描述符/绑定/扩展的示例

ejb-jar.xml中:

<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar xmlns="http://java.sun.com/xml/ns/javaee" version="3.0" metadata-complete="false">
  <enterprise-beans>
    <session>
      <ejb-name>RepositoryInstanceFacade</ejb-name>
      <resource-ref>
        <description>XA Message Manager Data Source</description>
        <res-ref-name>java:app/env/jdbc/MessageManagerDB</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <res-auth>Container</res-auth>
        <res-sharing-scope>Shareable</res-sharing-scope>
      </resource-ref>
    </session>
  </enterprise-beans>
</ejb-jar>

IBM-EJB-JAR-bnd.xml:

<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar-bnd xmlns="http://websphere.ibm.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://websphere.ibm.com/xml/ns/javaee http://websphere.ibm.com/xml/ns/javaee/ibm-ejb-jar-bnd_1_0.xsd"
  version="1.0">
  <session name="RepositoryInstanceFacade">
    <resource-ref name="java:app/env/jdbc/MessageManagerDB" binding-name="jdbc/MessageManagerDB"/>
  </session>
</ejb-jar-bnd>

IBM-EJB-JAR-ext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar-ext xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://websphere.ibm.com/xml/ns/javaee"
  xsi:schemaLocation="http://websphere.ibm.com/xml/ns/javaee http://websphere.ibm.com/xml/ns/javaee/ibm-ejb-jar-ext_1_0.xsd"
  version="1.0">
  <session name="RepositoryInstanceFacade">
    <resource-ref name="java:app/env/jdbc/MessageManagerDB" isolation-level="TRANSACTION_READ_COMMITTED" commit-priority="2"/>      
  </session>
</ejb-jar-ext>

应用程序代码,用于查找数据源并验证是否正在使用扩展的隔离级别:

DataSource ds = InitialContext.doLookup("java:app/env/jdbc/MessageManagerDB");
Connection con = ds.getConnection();
try {
    int iso = con.getTransactionIsolation();
    System.out.println("Isolation level is " + iso);
} finally {
    con.close();
}

如果上面的代码输出2(java.sql.Connection.TRANSACTION_READ_COMMITTED的值),而不是默认的隔离级别4,则表明正在应用绑定/扩展。 如果在此之后,您仍然没有看到提交优先级被尊重,那么它就是一个事务管理错误,我建议将其报告给IBM支持。