控制两阶段提交事务的提交顺序
Controlling commit order for a Two-Phase Commit transaction
我们在 Webshere Application Server 8.5.5 上有一个 java 应用程序 运行ning。在不同的 JVM 中有两个进程 运行ning。
该应用程序使用 IBM Webshere 队列管理器和 Oracle 11c 数据库进行一些集成。 JMS 和 JDBC 资源都配置为使用 XA t运行sactions。
进程 1:
- 从 MESSAGES 队列中读取消息并提取用于识别相关消息的消息键
- 将消息保存到数据库。
- 检查 KEYS table 中是否不存在消息密钥,如果不存在,则将其插入
- 仅当上述插入发生时它才会将消息键放入KEYS队列
- 提交 t运行saction
进程 2:
- 从 KEYS 队列
中获取消息密钥
- 从 KEYS table
中删除消息密钥
- 处理与从 MESSAGES table
接收到的消息密钥关联的所有消息
我们观察到,在大约 5% 的情况下,从 KEYS 队列中获取消息密钥后,有时 PROCESS 2找不到要从 KEYS table 中删除的记录,只是为了在几毫秒后变得可用。尝试多次删除它解决了这个问题,但很明显,即使 PROCESS 1 启用了 XA,它也会首先提交 JMS 资源,然后 JDBC 带来非常短的时间一段时间内数据处于不一致状态。
所以这是我的问题:
有没有办法强制 t运行saction 管理器先提交 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>
然而这并没有解决我们的问题。我相信我们不是唯一面临这个问题的人,但我只是 运行 不知道该尝试什么。我们最终将消息密钥放回 KEYS 队列中,这解决了问题,但在我看来这是一个非常非正统的解决方案,而不是关键的 24 x 7 的良好解决方案申请。
提前感谢您的意见。
更新
我在我的 ejb 应用程序的 META-INF 文件夹中添加了这个资源绑定文件 ibm-ejb-jar-bnd.xml 文件,但仍然没有成功。作为部署的一部分,我可以看到 IBM 操纵了该文件并将其运行sformed 成一个 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 最后提交,所以它仍然没有按预期工作。
根据我在评论中提出的问题,资源引用实际上并未用于查找资源,这就是 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 这意味着更新资源也将名称引用到相应的值。
更新:ejb 部署示例 descriptor/bindings/extensions 名称 java:app
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,这表明正在应用 bindings/extensions。
如果在此之后,您仍然没有看到 commit-priority 得到兑现,那么这是一个事务管理错误,我建议将其报告给 IBM 支持。
我们在 Webshere Application Server 8.5.5 上有一个 java 应用程序 运行ning。在不同的 JVM 中有两个进程 运行ning。 该应用程序使用 IBM Webshere 队列管理器和 Oracle 11c 数据库进行一些集成。 JMS 和 JDBC 资源都配置为使用 XA t运行sactions。
进程 1:
- 从 MESSAGES 队列中读取消息并提取用于识别相关消息的消息键
- 将消息保存到数据库。
- 检查 KEYS table 中是否不存在消息密钥,如果不存在,则将其插入
- 仅当上述插入发生时它才会将消息键放入KEYS队列
- 提交 t运行saction
进程 2:
- 从 KEYS 队列 中获取消息密钥
- 从 KEYS table 中删除消息密钥
- 处理与从 MESSAGES table 接收到的消息密钥关联的所有消息
我们观察到,在大约 5% 的情况下,从 KEYS 队列中获取消息密钥后,有时 PROCESS 2找不到要从 KEYS table 中删除的记录,只是为了在几毫秒后变得可用。尝试多次删除它解决了这个问题,但很明显,即使 PROCESS 1 启用了 XA,它也会首先提交 JMS 资源,然后 JDBC 带来非常短的时间一段时间内数据处于不一致状态。
所以这是我的问题:
有没有办法强制 t运行saction 管理器先提交 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>
然而这并没有解决我们的问题。我相信我们不是唯一面临这个问题的人,但我只是 运行 不知道该尝试什么。我们最终将消息密钥放回 KEYS 队列中,这解决了问题,但在我看来这是一个非常非正统的解决方案,而不是关键的 24 x 7 的良好解决方案申请。
提前感谢您的意见。
更新 我在我的 ejb 应用程序的 META-INF 文件夹中添加了这个资源绑定文件 ibm-ejb-jar-bnd.xml 文件,但仍然没有成功。作为部署的一部分,我可以看到 IBM 操纵了该文件并将其运行sformed 成一个 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 最后提交,所以它仍然没有按预期工作。
根据我在评论中提出的问题,资源引用实际上并未用于查找资源,这就是 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 这意味着更新资源也将名称引用到相应的值。
更新:ejb 部署示例 descriptor/bindings/extensions 名称 java:app
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,这表明正在应用 bindings/extensions。 如果在此之后,您仍然没有看到 commit-priority 得到兑现,那么这是一个事务管理错误,我建议将其报告给 IBM 支持。