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?
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