Note that there are some explanatory texts on larger screens.

plurals
  1. POJPA and Spring transactions - please explain
    primarykey
    data
    text
    <p>today I have coded a test case for my application, to see how transactions behave. And I have found that nothing works the way I thought it does.</p> <p>I have a Spring-based application using Hibernate as JPA provider, backed by MySQL. I have DAO objects, extending Spring's JpaDaoSupport. These are covered by Spring's transaction management.</p> <p>The test case I've created works like this: 1) An entity is created, with some counter set to 0. 2) Then two threads are created, which both call a DAO method incrementCounter() in a loop.</p> <p>I thought that when DAO methods are covered with transaction, then only one thread will be inside it (i.e., Spring will take care of synchronization). But this has proven to be false assumption.</p> <p>After (temporary) solving this by adding <code>synchronized</code> to the DAO method, I found out that Hibernate does not store the changes made by the DAO method, and the other thread, when find()ing the entity, has old data. Only explicit call of <code>this.getJpaTemplate().flush();</code> helped.</p> <p>I also thought that entity manager would give me the same entity instance from the cache of the persistence context, but this is also false. I have checked hashCode() and equals(), and they are fine - based on entity's bussines key.</p> <p>Any comments welcome, as it seems I miss some basic concepts of how JPA / Spring works with transactions.</p> <ol> <li>Should DAO methods be <code>synchronized</code>?</li> <li>Should I call flush() at the end of every DAO method?</li> <li>Is spring responsible for making the calls to DAO methods behave transactionally? (i.e. not letting two threads work with the same entity at the same time)</li> <li>If not, how do I achieve this?</li> </ol> <p>Note that in my test case, I use a single DAO object, but that should be OK as Spring's beans are singletons - right?</p> <p>Thanks for any help.</p> <pre><code>public class EntityDaoImpl extends JpaDaoSupport implements EntityDao { public synchronized void incrementCounter( String znacka ) { String threadName = Thread.currentThread().getName(); log.info(threadName + " entering do incrementCounter()."); Entity ent = this.getJpaTemplate().find( Entity.class, znacka ); log.info("Found an entity "+ent.getZnacka()+"/"+ent.hashCode()+" - " + ObjectUtils.identityToString( ent ) ); log.info(threadName + ": Actual count: "+ent.getCount() ); ent.setCount( ent.getCount() + 5 ); int sleepTime = threadName.endsWith("A") ? 700 : 50; try { Thread.sleep( sleepTime ); } catch( InterruptedException ex ) { } ent.setCount( ent.getCount() + 5 ); this.getJpaTemplate().flush(); log.info(threadName + " leaving incrementCounter()."); } } </code></pre> <hr> <p>Without <code>synchronized</code> and <code>flush()</code>, this was giving me output like</p> <pre><code>Thread A: Actual count: 220 ... Thread B: Actual count: 220 ... Thread A: Actual count: 240 ... Thread B: Actual count: 250 ... Thread A: Actual count: 250 </code></pre> <p>...etc, meaning that one thread has overwriten the changes from the other.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload