Search code examples
javahibernatehibernate-session

Hibernate session cache behavior in clustered environment?


I was asked the following question in one of the interviews I attended -

Let's say we have multi-clustered application servers, where each has created its own SessionFactory (pointing to same single DB). One server retrieves a record [Person with ID = 1] which caches the same in the session (s1), which is still open.

In the meantime, another server, opens another session (s2) and updates the Person record with ID = 1. Now what happens to the Person record cached within s1? Will it be a stale record?

I created a small program to simulate the scenario on single JVM. To my surprise, the session cache keeps the stale data, despite of creating 2 sessions from the same SessionFactory. Even the s1.flush() didn't help.

    Session s1 = HibernateManager.getInstance().openNewSession();
    System.out.println("Opened session s1");
    Person p1 = s1.get(Person.class, 1);
    System.out.println("Retreived person with ID = 1 using s1, Name is");
    System.out.println(p1.getName()); //prints Test1
    
    Session s2 = HibernateManager.getInstance().openNewSession();
    System.out.println("Opened session s2");
    Person p2 = s2.get(Person.class, 1);
    System.out.println("Retreived person with ID = 1 using s2, Name is");
    System.out.println(p2.getName()); //prints Test1
    p2.setName("Test2");
    Transaction tx = s2.beginTransaction();
    s2.saveOrUpdate(p2);
    tx.commit();
    HibernateManager.getInstance().close(s2);
    System.out.println("Changed name and updated - closed s2");     
    
    p1 = s1.get(Person.class, 1);
    System.out.println("Retreived person with ID = 1 using s1 AGAIN, Name is");
    System.out.println(p1.getName()); //prints Test1
    
    System.out.println("Flushed s1");
    s1.flush();
    
    p1 = s1.get(Person.class, 1);
    System.out.println("Retreived person with ID = 1 using s1 AGAIN, Name is");
    System.out.println(p1.getName()); //still prints Test1. I was expecting Test2 because I flushed s1 (synced the session with DB)
    
    HibernateManager.getInstance().close(s1);

My question is, do session invalidate the cache if the same record gets updated using another session?


Solution

  • Yes p1 will be a stale record. If you update p1, on session flush or transaction commit of session s1, p1 will overwrite p2's update.

    To prevent this you can use Optimistic locking. Specify a version-number (@Version in java source code) (or last-updated-date if you have such a column) and instruct hibernate to use this column to version updates. In which case if we update p1, on session flush hibernate would perform a select before update, see that the version information doesn't match (someone got in, in between and updated the record) and throw a StaleObject exception