Quick Start

 

Products & Services

 

Training Dates

US - San Francisco
Oct 6-7, 2010
Nov 11-12, 2010
Dec 2-3, 2010
Feb 4-5, 2011

India - Delhi
Dec 2-3, 2010

See training details.

 

Blogs & Tweets

JTA

New feature in Ehcache 2.0 JTA is supported in versions of Ehcache 2.0 and higher.

Ehcache acts as an XAResouce and participates in JTA ("Java Transaction API") transactions.

Transaction Managers

Automatically Detected Transaction Managers

Ehcache automatically detects and uses the following transaction managers in the following order:

  • GenericJNDI (e.g. Glassfish, JBoss, Weblogic, JTOM and any others that register themselves in JNDI at the standard location of java:/TransactionManager
  • Websphere
  • Bitronix
  • Atomikos

No configuration is required; they work out of the box.

The first found is used.

Configuring a Transaction Manager

If you Transaction Manager is not in the above list or you wish to change the priority you need to configure your own lookup class and specify it in place of the DefaultTransactionManagerLookup in the ehcache.xml config::

<transactionManagerLookup
 class= "net.sf.ehcache.transaction.manager.DefaultTransactionManagerLookup"
 properties="" propertySeparator=":"/>

You can also provide a different location for the JNDI lookup by providing the jndiName property to the DefaultTransactionManagerLookup.

The example below provides the proper location for the TransactionManager in GlassFish v3:

<transactionManagerLookup
 class="net.sf.ehcache.transaction.manager.DefaultTransactionManagerLookup"
 properties="jndiName=java:appserver/TransactionManager" propertySeparator=";"/>

Configuring a Cache for JTA

JTA is enabled on a cache by cache basis with the transactionalMode cache attribute

The allowed values are xa and off. By default it is off.

Enabling a cache for JTA is shown in the following example:

    <cache name="xaCache"
        maxElementsInMemory="500"
        eternal="false"
        timeToIdleSeconds="300"
        timeToLiveSeconds="600"
        overflowToDisk="false"
        diskPersistent="false"
        diskExpiryThreadIntervalSeconds="1"
        transactionalMode="xa">
  </cache>

Note that in Ehcache 2.0 JTA requires Terracotta serialization value mode otherwise a a CacheException will be thrown on start up. Standalone Ehcache is supported as of Ehcache 2.1.0

Using a JTA Cache

All or nothing

If a cache is enabled for JTA all operations on it must happen within a transaction context, otherwise a TransactionRequiredException will be thrown.

Change Visibility

The isolation level offered in Ehcache JTA is READ_COMMITTED. Ehcache is an XAResource. Full two-phase commit is supported.

Specifically:

  • All mutating changes to the cache are transactional including put, remove, putWithWriter, removeWithWriter and removeAll.
  • Mutating changes are not visible in the local JVM to or across the cluster until COMMIT has been called.
  • Until then, read such as by cache.get(...) by other transactions will return the old copy. Reads do not block.

Write-behind and Write-through

If your XA enabled cache is being used with a writer, write operations will be queued until transaction commit time. Solely a Write-through approach would have its potential XAResource participate in the same transaction. Write-behind, while supported, should probably not be used with an XA transactional Cache, as the operations would never be part of the same transaction. Your writer would also be responsible for obtaining a new transaction...

Using Write-through with a non XA resource would also work, but there is no guarantee the transaction will succeed after the write operation have been executed successfully. On the other hand, any thrown exception during these write operations would cause the transaction to be rolled back by having UserTransaction.commit() throw a RollbackException.

Architecture

Bootstrapping

Transactional support is implemented at the Store level, through XaTransactionalStore. The store actually decorates the underlying MemoryStore implementation, augmenting it with transaction isolation and two-phase commit support.

During it's initialization, the Cache will lookup the TransactionManager using the provided TransactionManagerLookup implementation. Using the TransactionManagerLookup.register(XAResouce): void callback, the newly created XAResource is potentially registered with the TransactionManager.

That same TransactionManager will from there on be used by the Cache to access the current transaction on all transactional method calls.

The store is automatically configured to copy every Element read from the cache or written to it. Cache is copy-on-read and copy-on-write.

A day in the life of a transactional Cache

Every read from the Cache, or remove() without a previous get(), will have the transactional track versioning information for these cache values. This version information will be checked against at commit time, to make sure we're still mutating the same information.

Write operation to the cache (puts and removes) are not effectively executed against the underlying memory store. Rather a local transaction context is being altered. It queues all commands to be executed against the Store at commit time. This context also alters the behavior of cache accesses: e.g. within the same transaction a put and then a getSize call will reflect that previous put, while other transaction would not be impacted. This gives read_commited isolation.

During the two phase commit, the context is first prepared: where all keys to be altered are checked for consistency against the optimistic locking mechanism. If a key to be updated or removed has since been changed by a commited transaction, the transaction will be rolled back. For each key a write lock is acquired, version checked and the old value is copied to a temporary "guarding" store. That store is always queried before the real underlying memory store is. That way, while write locked, old values that are about to be updated can still be read, non blocking, from the "oldVersionStore". If all keys could be validated and write locked the prepare operation as finished successfully and Ehcache votes OK on commit.

If all other XAResource eventually vote OK, the transaction is committed: the old value(s) are removed and write-locks are released. If not, the old values are copied back to the store and the lock released.

Failure

As specified by the JTA specification, only prepared transaction data is recoverable. Which means that any transaction still alive at VM failure will be lost. Since all these operations are non locking, the cluster isn't suffering from these.

Prepared data on the other hand, is persisted to the L2 and locks on the memory are being held. Should the L1 come back up before the locks timed out, like network failure, the VM will be able to keep doing its work.

Recovery

Should the XA recovery scan be required by the transaction manager, Ehcache will provide all Xid prepared, but these will only be able to be rolled back. Indeed when locks time out, no guarantee can be made about the locked keys and their value. If the transaction manager still asks Ehcache to commit these, a HeuristicException will be thrown.

Sample Apps

We have three sample applications showing how to use JTA with a variety of technologies.

JTA Sample App

This sample application uses JBoss application server. It shows an example using User managed transactions. While we expect most people will use JTA from within Spring or EJB where the container rather than managing it themselves, it clearly shows what is going on.

The following snippet from our SimpleTX servlet shows a complete transaction.

   Ehcache cache = cacheManager.getEhcache("xaCache");

    UserTransaction ut = getUserTransaction();

    printLine(servletResponse, "Hello...");
    try {
        ut.begin();
        int index = serviceWithinTx(servletResponse, cache);
        printLine(servletResponse, "Bye #" + index);
        ut.commit();

    } catch(Exception e) {
        printLine(servletResponse,
            "Caught a " + e.getClass() + "! Rolling Tx back");
        if(!printStackTrace) {
            PrintWriter s = servletResponse.getWriter();
            e.printStackTrace(s);
            s.flush();
        }
        rollbackTransaction(ut);
    }

The source code for the demo can be checked out from http://svn.terracotta.org/svn/forge/projects/ehcache-jta-sample/trunk

A README.txt explains how to get the JTA Sample app going.

JTA Banking Application

The Idea of this application is to show a real world scenario. AwWeb app reads account transfer messages from a queue and tries to execute these account transfers.

With JTA turned on, failures are rolled back so that the cached account balance is always the same as the true balance summed from the database.

This app is a Spring-based Java web app running in a Jetty container. It has (embedded) the following components:

  • A JMS Server (ActiveMQ)
  • 2 databases (embedded Derby XA instances)
  • 2 caches (JTA Ehcache)

    All XA Resources are managed by Atomikos TransactionManager. Transaction demarcation is done using Spring AOP's @Transactional annotation.

    You can run it with: mvn clean jetty:run. Then point your browser at: http://localhost:9080.

    To see what happens without XA transactions:

    mvn clean jetty:run -Dxa=no

        The source code for the demo can be checked out from
        {{http://svn.terracotta.org/svn/forge/projects/ehcache-jta-banking/trunk}}
    
        A README.txt explains how to get the JTA Sample app going.
    
    
    **  Examinator
    
        Examinator is our complete application that shows many aspects of caching in one web based Exam application,
         all using the Terracotta Server Array.
    
        Check out from {{http://svn.terracotta.org/svn/forge/projects/exam/}}
    
    
    **  Hibernate Transactions
    
        Ehcache is a "transactional" cache for Hibernate purposes. The <<<net.sf.ehcache.hibernate.EhCacheRegionFactory>>>
        has support for Hibernate entities configured with <cache usage="transactional"/>.
    
    
    *   Limitations
    
        There is one limitation left in this second release of JTA for Ehcache.
    
    *   FAQ
    
    **  How do I make WebLogic 10 work with Ehcache JTA?
    
        WebLogic uses an optimization that is not supported by our implementation. By default WebLogic 10 will spawn threads to
        start the Transaction on each XAResource in parallel. As we need transaction work to be performed on the same Thread, you will have
        to turn this optimization off by setting <<<parallel-xa-enabled>>> option to <<<false>>> in your domain configuration :
    

jta ... checkpoint-interval-seconds300/checkpoint-interval-seconds parallel-xa-enabledfalse/parallel-xa-enabled unregister-resource-grace-period30/unregister-resource-grace-period ... /jta ---