开发者

When should Transaction.delistResource() be called?

We utilize in-memory LRU caches for several different models across our application. To avoid issues arising from transactions being rolled back (like stale entries), a notion of transactional c开发者_如何学Pythonaches was added: A temporary cache is created for each transaction, and then entries are discarded if it gets rolled back or they are copied over to the main cache for that model if it's committed.

To accomplish this, the cache implements XAResource and overrides the commit() and rollback() methods. Whenever a new Transaction wants to access some data that's not in the main cache, a transactional cache is created and passed into enlistResource().

The problem is that I was trying to call delistResource() on the cache instance within the commit() and rollback() methods, which was throwing an IllegalStateException, saying the transaction was already marked for rollback (or commit). So I was wondering... is it okay to not delist the cache as a resource (in other words, it already gets delisted as part of the rollback or commit process), or is there another point in the flow where it should be called?


It's not the XAResource's methods that call delistResource, it's the app server's Transaction implementation. If you want a resource to be delisted, obtain the transaction and call delist on that, it will call end() on the resource for you as needed. The transaction manager likewise calls end() implicitly as part of the termination processing, so you don't do so manually at commit or rollback. The only case in which you need to handle a delist is when using the same resource instance in multiple transaction contexts. For example


    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

Depending on your cache implementation you may need to delist on suspend and enlist again on resume, but not for commit or rollback. Alternatively you check the transaction context on each makeUpdate() call rather than relying on the sequence of enlist/delist calls to update the effective tx context held by the resource instance.

This stuff is hard, due to the poor mapping between the procedural XA spec and the more or less Object Oriented JTA spec. Frankly you are probably better off leaving it to the experts. JBoss Infinispan for example provides an open source transactional cache that takes care of all this for you and offers plenty of other features besides.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜