views:

123

answers:

2

I have a multi-threaded, multi-server web application with hibernate and spring managing transactions with AOP. The problem is, I need to maintain in-memory data and keep it current with the state of the database...essentially I'm implementing an in-memory cache.

Now, is there any way to make my in-memory pojos transactional on the same level as the hibernate/spring transactionality? I have service calls layered 30 classes deep, and I never know where the commit will occur. What are my options?

+2  A: 

If I understand well your need, you are asking something delicate, in some contexts. Let me try an example, to check if I understand correctly:

  1. Thread T1 reads pojo P in the cache, gets version P1.
  2. Thread T2 reads pojo P in the cache, gets version P1.
  3. Thread T2 starts transaction, read the same pojo, modify a value which creates version P2.
  4. Thread T1 reads pojo P in the cache, still gets version P1. This requires that for point 3, T2 received a copy P2 of version P1, not the same object.
  5. Thread T2 saves P, nothing changes for either T1 or T2, they have different versions.
  6. Thread T2 closes the transaction:
    a. if rollback, T2 will then use P1, as T1 does.
    b. if commit, T2 will continue using P2. But now T1 must use P2 also.

You can see that this is a complex issue, don't underestimate it. There are many issues to be solved, on the theoretical level already (and you will have more when you code...). Your architecture will need to be really clear, if you want to use it successfully. If not, you risk your mental sanity ;-)

First, You need to make sure you really want something like that!


If you really want that ..

I suggest using technical code (AOP, ThreadLocal) to hide this tricky complexity from your functional code.

  • It is probable that your commit/rollback is already done via AOP, so this should be no problem.

  • To hide the retrieving of instances of P (sometimes the instance in the Stored cache, sometimes a copy) : Use a class called Store to store the values in the cache, have a ThreadLocal variable of type Store. I would use a ThreadLocal variable for your current thread:

    • the Store instance can only be changed in your transactional AOP code, not in your functional code
    • your functional code uses the current ThreadLocal instance for manipulating the entities (saving etc...)
    • when outside a transaction, the ThreadLocal instance is the cached one, let's call it CACHE.
    • entering a transaction sets a different ThreadLocal instance for current thread ; that class is a subclass of Store, that will return copies of the caches objects as you ask for them ; the class will also memorise if some are saved (so you need to save them using this special API, or notify this in your regular saving API)
    • rollbacking a transaction would throw away the ThreadLocal instance, reinstalling the CACHED one for current thread
    • commiting a transaction would take all memorized database operation in the ThreadLocal instance, apply that to modify the CACHED instance, and reinstall the CACHED instance for current thread
KLE
+1  A: 

Does using Hibernate's 2nd level cache not satisfy your requirements? JBoss Cache provider is both distributed and transactional.

If that doesn't work for you, you'll have to explain why and what is it you're really trying to achieve in order to get meaningful responses.

ChssPly76