Disclaimer: I haven't looked at the ehcache src, so I'm just speculating.
Now, if you enable debug level logging for the caching system and SQL, you will see messages in the following order (using ehcache):
Code:
13:18:03,582 DEBUG ReadWriteCache:106 - Invalidating: 941
13:18:03,586 DEBUG SQL:237 - update blah blah
13:18:03,746 DEBUG ReadWriteCache:227 - Updating: 941
13:18:03,749 DEBUG ReadWriteCache:243 - Updated: 941
If nothing else, this strongly suggests that the instance of the object in the cache is NOT the same instance that you're manipulating. Rather, what happens is that when you commit your transaction the instance in the cache is first marked invalid, then the actual db transaction takes place, and if it's successful the instance in the cache is updated by copying the properties. This, in effect, makes ehcache behave pretty much according as READ COMMITTED isolation level, which is the default isolation level for most databases.
However, I suspect that ehcache doesn't ensure that the cache updates are atomic if you use nonstrict-read-write, i.e. if you update many rows in a single db transaction the updated cache objects are available for other threads immediately after update, and not after all the cache objects in the transaction are updated. Or can anybody confirm that I'm wrong here (javadocs at least mention that a NonstrictReadWriteCache never locks the cache)?
If you use read-write, I think that ehcache locks the cached objects, which should make sure that cache updates for a single db transaction are also atomic.
Now, the meaning of transactional in the context of TreeCache probably means that TreeCache participates in the same transaction as the actual DB operations (it depends on JTA). This certainly ensures that updating many cache objects in a single transaction is an atomic operation. Also, I'm quite sure Treecache uses some 2-phase commit protocol to ensure that cache updates are successfully propagated to all the nodes in a cluster.