从一个错误谈谈事务管理
来源:互联网 发布:淘宝省钱app有哪些 编辑:程序博客网 时间:2024/06/05 07:32
最近在产品中发现了一个错误,和分布式事务相关,仔细梳理了一下,还发现不少值得深究的东西,下面就分享给大家。
错误堆栈信息比较长,只摘出关键的一段:
[2/28/12 0:57:28:195 MST] 00000016 SystemErr R Caused by: javax.resource.ResourceException: enlist: caught Exception[2/28/12 0:57:28:195 MST] 00000016 SystemErr R at com.ibm.ejs.j2c.LocalTransactionWrapper.enlist(LocalTransactionWrapper.java:696)[2/28/12 0:57:28:195 MST] 00000016 SystemErr R at com.ibm.ejs.j2c.ConnectionManager.lazyEnlist(ConnectionManager.java:2186)[2/28/12 0:57:28:195 MST] 00000016 SystemErr R at com.ibm.ws.rsadapter.spi.WSRdbManagedConnectionImpl.lazyEnlist(WSRdbManagedConnectionImpl.java:2569)[2/28/12 0:57:28:195 MST] 00000016 SystemErr R at com.ibm.ws.rsadapter.jdbc.WSJdbcConnection.beginTransactionIfNecessary(WSJdbcConnection.java:714)[2/28/12 0:57:28:195 MST] 00000016 SystemErr R ... 127 more[2/28/12 0:57:28:195 MST] 00000016 SystemErr R Caused by: com.ibm.ws.Transaction.IllegalResourceIn2PCTransactionException: Illegal attempt to enlist multiple 1PC XAResources[2/28/12 0:57:28:195 MST] 00000016 SystemErr R at com.ibm.ws.tx.jta.RegisteredResources.enlistResource(RegisteredResources.java:864)[2/28/12 0:57:28:195 MST] 00000016 SystemErr R at com.ibm.ws.tx.jta.TransactionImpl.enlistResource(TransactionImpl.java:1781)[2/28/12 0:57:28:195 MST] 00000016 SystemErr R at com.ibm.ws.tx.jta.TranManagerSet.enlistOnePhase(TranManagerSet.java:612)[2/28/12 0:57:28:195 MST] 00000016 SystemErr R at com.ibm.ejs.j2c.LocalTransactionWrapper.enlist(LocalTransactionWrapper.java:593)[2/28/12 0:57:28:195 MST] 00000016 SystemErr R ... 130 more从错误信息可以看到Illegal attempt to enlist multiple 1PC XAResources,错误的原因似乎和分布式事务相关,那么一个自然而然的想法就是把non-xa的数据源改为XA数据源,问题不就解决了。 无非就是牺牲一点性能,但能保证程序正常工作, 然而事实是如此吗?通过试验我们发现,把这个数据源改为XA后,运行过程中在执行DDL的时候会出错。看来此路不通。什么原因了?原来对于某个RM,如果它执行了一个不可回滚的操作,那么它是不能参与到两阶段事务提交的, 因为两阶段提交的第二阶段是有可能回滚的, 如此一来,就有冲突了。顺便说一下, 这也是为什么下面这些操作是不能出现在分布式事务中的,
执行DDL语句,例如create table; 执行savepoint; 使用db link操作 等等,总而言之,这些操作有个共同点就是他们是不能回滚的,或者是隐式提交。
接下来地思路就是,如何在分布式事务中使用non-xa 的数据源, 会有哪些限制。 在这里,需要提到应用服务器,我们以websphere和weblogic为例, 由于普通的数据源是不支持两阶段提交的,但是在实际中,经常会碰到这种情况,就是已有的操作使用Non-XA数据源,这个操作需要成为分布式事务的一部分,weblogic 提供了模拟两阶段提交,websphere提供了last participant in 作为解决方案。
Select this option if you want to enable non-XA JDBC connections from the data source to participate in global transactions using the one-phase commit transaction processing. With this option, no other resources can participate in the global transaction.(使用此选项,使用连接的事务分支始终返回事务准备阶段的成功信息。此选项提供了性能优势,但在某些失败情况下也存在破坏数据的风险。只有在应用程序可允许出现启发性错误情况时才能选择此选项。)WebLogic 9中的LLR特性不应该与“Emulate Two-Phase Commit(模拟两阶段提交)”相混淆,后者是以前版本的JDBC连接池层的选项。两者之间有着微妙而重要的区别。根据BEA WebLogic 8的说明文档:
当选中Emulate Two-Phase Commit for non-XADriver选项(EnableTwoPhaseCommit设为true)时,非XA的JDBC资源通常在调用XAResource.prepare()方法时返回XA_OK。该资源试图提交或回滚它的本地事务以响应随后的XAResource.commit()或XAResource.rollback() 调用。如果该资源提交或回滚失败,就会产生一个启发式错误。其结果是应用程序的数据可能会不一致。
而对于LLR,它是针对应用服务器或者说事物管理器上的操作,在具有 LLR 参与者的全局两阶段提交 (2PC) 事务中,WebLogic Server 事务管理器执行下列基本步骤:
在所有其他(符合 XA 的)事务参与者上调用准备。将提交记录插入 LLR 参与者的表中(而不是基于文件的事务日志中)。提交 LLR 参与者的本地事务(包括事务提交记录插入和应用程序的 SQL 工作)。在所有其他事务参与者上调用提交。在事务成功完成后,从容地将数据库事务日志条目删除(作为未来事务的一部分)。
然而在整个程序中,我们仅仅配置一个non-xa的数据源,无论如何不会这样的问题了,因为LPS是可以有一个non-XA的数据源参与全局事务的。最后通过分析,终于发现了问题。在获取数据源时,我们用了JNDI,然后有的时候用的是绝对路径,如java:comp/ 有的时候直接用相对路径名,例如 user.databasepool, 在应用服务器中,虽然他们实际是指向同一个数据源,然后由于引用的路径地不用,造成WS认为是两个non-XA数据源参与其中,至此,解决的办法也很简单,采用同一种路径去获取数据源,问题解决!
通过这个例子可以看出,在决定数据源及其事务时,有下面这些注意的,
本地事务会优于分布式事务,无论是在性能还是可靠性上,所以我觉得应该优先使用本地事务,例如SAP好像就提倡使用一个数据库,本地事务,分布式事务从概念上来说很好,但是实际实现还是有很多问题的。
如果在某些情况下,必须使用分布式事务,例如多个数据库,JMS等,要考虑全局事务尽量使用XA驱动,对于LLR和EPC,以及LPS,虽然他们可用,但并不安全,相对来说LLR>EPC。
如果使用LPS LLR等还是有冲突,例如两个non-XA数据源要参与全局事物,这时,很可能需要把你的事物分拆成单个的小事务,避免这种大事务包含多个non-xa的情况。
- 从一个错误谈谈事务管理
- 从一个简单的例子谈谈package与import机制
- 从一个简单的例子谈谈package与import机制
- 从一个简单Java程序来谈谈重构
- 从一个简单的Java单例示例谈谈并发
- 从一个简单的Java单例示例谈谈并发
- 从一个错误引出的思考
- 从一个严重的错误中恢复
- 谈谈Linux打补丁的原理以及如何判别打补丁的错误 --- 从补丁学内核
- 谈谈Linux打补丁的原理以及如何判别打补丁的错误 --- 从补丁学内核
- 谈谈Linux打补丁的原理以及如何判别打补丁的错误 --- 从补丁学内核
- 谈谈Linux打补丁的原理以及如何判别打补丁的错误 --- 从补丁学内核
- 谈谈Linux打补丁的原理以及如何判别打补丁的错误 --- 从补丁学内核
- 从一个构造函数谈谈的代码的封装性和怎么表现自己的意图
- 谈谈移动应用设计——从一个普通开发者的角度
- 谈谈移动应用设计——从一个普通开发者的角度
- 从一个简单的例子谈谈package与import机制(上)
- 从一个简单的例子谈谈package与import机制(下)
- 给父母的四个建议
- 计算n bit的整数中有多少bit 为1
- Agile measurement
- Java建立字符两种方式的区别
- oracle 内连接(inner join)、外连接(outer join)、全连接(full join)
- 从一个错误谈谈事务管理
- 电能质量监测装置人机界面的实现
- sasa
- Ext.data.Store动态修改url
- __stdcall约定
- 一分钟制作U盘版BT3 - 有图滴儿 bt3破解教程
- POJ2752 Seek the Name, Seek the Fame
- 多目运算符
- ZOJ 1084 Channel Allocation