我们在应用程序中为几种不同的模型使用内存中的LRU缓存。为了避免回滚事务引起的问题(如过时条目),添加了事务缓存的概念:为每个事务创建临时缓存,然后如果条目被回滚或者它们被复制到主要条目,则会丢弃条目如果已提交,则缓存该模型。
要实现此目的,缓存会实现XAResource
并覆盖commit()
和rollback()
方法。每当新的Transaction
想要访问不在主缓存中的某些数据时,就会创建一个事务缓存并将其传递到enlistResource()
。
问题是我试图在delistResource()
和commit()
方法中的缓存实例上调用rollback()
,该方法抛出IllegalStateException
,说交易是已标记为回滚(或提交)。所以我在想......是否可以不将缓存作为资源删除(换句话说,它已经作为回滚或提交过程的一部分被删除),或者是否还有其他一点应该叫它的流程?
答案 0 :(得分:1)
调用delistResource的不是XAResource的方法,而是app服务器的Transaction实现。如果您想要对资源进行删除,获取事务并调用deist,它将根据需要为您调用资源上的end()。事务管理器同样作为终止处理的一部分隐式调用end(),因此您不必在提交或回滚时手动执行此操作。您需要处理退市的唯一情况是在多个事务上下文中使用相同的资源实例。例如
Cache c = getCache(); c.makeUpdate(); // no transaction running, should auto commit. tx.begin(); // start tx A c.makeUpdate(); // transactional within A tx.suspend(); tx.begin(); // start tx B c.makeUpdate(); // transactional within B tx.commit(); //end B tx.resume(A); tx.commit(); // end A
根据您的缓存实现,您可能需要在恢复时退出挂起并再次登记,但不能用于提交或回滚。或者,您可以检查每个makeUpdate()调用的事务上下文,而不是依赖于enlist / delist调用的序列来更新资源实例持有的有效tx上下文。
由于程序XA规范与或多或少的面向对象的JTA规范之间的映射不佳,这个问题很难实现。坦率地说,你最好把它留给专家。例如,JBoss Infinispan提供了一个开源事务缓存,可以为您处理所有这些,并提供许多其他功能。