代码之家  ›  专栏  ›  技术社区  ›  Julian

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

  •  1
  • Julian  · 技术社区  · 8 年前

    我们有一个java应用程序运行在WebSphereApplicationServer8.5.5上。有两个进程在单独的JVM中运行。 应用程序正在使用IBM Webhere队列管理器和Oracle 11c数据库进行一些集成。JMS和JDBC资源都配置为使用XA事务。

    过程1:

    1. 阅读来自 消息 排队并提取用于标识相关消息的消息密钥
    2. 将消息保存到数据库。
    3. 检查消息密钥是否不存在于 钥匙 表,如果没有,则插入
    4. 仅当发生上述插入时 它将消息密钥放入 钥匙 队列
    5. 提交事务

    流程2:

    1. 钥匙 队列
    2. 从中删除消息键 钥匙 桌子
    3. 处理与从接收到的消息密钥相关联的所有消息 消息 桌子

    我们观察到,在从 钥匙 流程2 有时无法从中找到要删除的记录 钥匙 表仅在毫秒后可用。多次尝试删除它修复了问题,但很明显,即使 流程1 如果启用了XA,它首先提交JMS资源,然后JDBC在很短的时间内将数据置于不一致的状态。

    所以我的问题是:

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

    我们发现这个 IBM knowledge center 我们尝试如下配置提交优先级:

    <?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>
    

    然而,这并没有解决我们的问题。我相信我们不是唯一面临这个问题的人,但我只是不知道应该做些什么。最后,我们将消息键放回 钥匙 排队解决了问题,但在我看来,这是一个非常非正统的解决方案,而不是一个关键的24 x 7应用程序的好解决方案。

    提前感谢您的投入。

    更新 我添加了这个资源绑定文件ibm ejb jar bnd。我的ejb应用程序的META-INF文件夹中的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 回复  |  直到 8 年前
        1
  •  0
  •   njr    8 年前

    根据我在评论中提出的问题,实际上没有使用资源引用来查找资源,这就是为什么没有遵守提交优先级属性的原因。在问题的更新部分,您通过为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\u READ\u COMMITTED的值),而不是默认的隔离级别4,则表明正在应用绑定/扩展。 如果在这一点之后,您仍然没有看到提交优先级得到遵守,那么这是一个事务管理错误,我建议将其报告给IBM支持部门。

    推荐文章