-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 1 post ] 
Author Message
 Post subject: Hibernate in concurrent transaction doesn`t load data commit
PostPosted: Fri Jul 20, 2012 1:28 am 
Newbie

Joined: Fri Jul 20, 2012 1:25 am
Posts: 1
In our application we have critical section of code accessed by concurrent transactions. This critical section is guarded by database lock: SELECT FOR UPDATE. And we came to an issue when updates commited by one transaction are not available in another queued concurrent transaction.

We are using Spring 3.1, Hibernate 4.2.0 , Mysql 5. Transaction isolation level is READ_COMMITTED. For querying the database we use JPA EntityManager. Please, pay attention that coming snippet extracts Hibernate session from it. We did it intentionally to demonstrate that problem is somewhere in Hibernate, probably, Hibernate cache.

Here comes the code snippet demonstrating the issue. runTransaction method is launched in two concurrent transactions started under two different Hibernate sessions. First Transaction1 is started, then Transaction2. Both of them try to acquire lock. But Transaction2 loads an object before acquiring the lock. After passing into critical section (Transaction1 is already comitted) it makes sure that the object is not in Hibernate cache and loads the object, which was updated by Transaction1. Unfortunately, it loads the version object same to one loaded before acquiring lock, so further updating fails with StaleObjectException.

Does somebody know why Transaction2 loads the old version of object after it is updated by Transaction1? We are sure, that object is updated in database by Transaction1. If we try to load it using Spring JdbcTemplate or Hibernate StatelessSession in the scope of Transaction2, update version is loaded.

Code:
private void runTransaction(EntityManager entityManager, String name) {
    SessionFactory sf = ((HibernateEntityManagerFactory)emf).getSessionFactory();

    Session statefullSession = sf.openSession();

    System.out.println("*** Starting " + name + " ***");
    statefullSession.beginTransaction();

    BuildingType bt = null;
    //UNCOMMENT to get javax.persistence.OptimisticLockException: org.hibernate.StaleObjectStateException
    //Hibernate caches object and doesn`t notice changed made in Transaction1 later in the code
    if (name.equals("Transaction2")) {
        //Load object in Transaction2, but before obtaining lock
        System.out.println("*** Bean just before obtaining lock in " + name + " ***");
        bt = entityManager.find(BuildingType.class, 1L);
        System.out.println(name + ": " + bt);
    }

    entityManager.createNativeQuery("SELECT count(*) FROM client_cleaner_lock FOR UPDATE").getSingleResult();
    System.out.println("*** Lock in " + name + " ***");

    if (name.equals("Transaction1")) {
        bt = (BuildingType)statefullSession.get(BuildingType.class, 1L);

        System.out.println(name + ": " + bt);
        bt.setName(name);

        //Make sure, that Transaction2 loads original object, unmodified by Transaction1
        if (name.equals("Transaction1")) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        statefullSession.update(bt);
    } else if (name.equals("Transaction2")) {
        statefullSession.clear();
        System.out.println(statefullSession.contains(bt));

        //!!! Returns object loaded before obtaining lock in Transaction2, not updated by Transaction1 !!!
        bt = (BuildingType)statefullSession.get(BuildingType.class, 1L);

        System.out.println(name + ": " + bt);
        bt.setName(name);

        statefullSession.update(bt);
    }

    statefullSession.getTransaction().commit();
}


And here comes the output:
Code:
*** Starting Transaction1 ***
*** Lock in Transaction1 ***
Transaction1: Id: 1, Version: 0, Name: Apartment
*** Starting Transaction2 ***
*** Bean just before obtaining lock in Transaction2 ***
Transaction2: Id: 1, Version: 0, Name: Apartment
*** Lock in Transaction2 ***
false
Transaction2: Id: 1, Version: 0, Name: Apartment
Exception in thread "Thread-4" org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 1 post ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.