集群环境中的 Hibernate 会话缓存行为?
Hibernate session cache behavior in clustered environment?
在我参加的一次采访中有人问我以下问题 -
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?
我创建了一个小程序来模拟单个 JVM 上的场景。令我惊讶的是,会话缓存保留了陈旧的数据,尽管从同一个 SessionFactory
创建了 2 个会话。即使 s1.flush()
也无济于事。
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);
我的问题是,如果使用另一个会话更新同一条记录,session
是否会使缓存失效?
是的,p1 将是一个陈旧的记录。如果更新 p1,在会话 s1 的会话刷新或事务提交时,p1 将覆盖 p2 的更新。
要防止这种情况,您可以使用乐观锁定g。指定一个版本号(java 源代码中的@Version
)(如果有这样的列,则为最后更新日期)并指示休眠使用此列进行版本更新。在这种情况下,如果我们更新 p1,会话刷新休眠将在更新前执行 select,查看版本信息不匹配(有人进入,更新记录)并抛出 StaleObject 异常
在我参加的一次采访中有人问我以下问题 -
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?
我创建了一个小程序来模拟单个 JVM 上的场景。令我惊讶的是,会话缓存保留了陈旧的数据,尽管从同一个 SessionFactory
创建了 2 个会话。即使 s1.flush()
也无济于事。
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);
我的问题是,如果使用另一个会话更新同一条记录,session
是否会使缓存失效?
是的,p1 将是一个陈旧的记录。如果更新 p1,在会话 s1 的会话刷新或事务提交时,p1 将覆盖 p2 的更新。
要防止这种情况,您可以使用乐观锁定g。指定一个版本号(java 源代码中的@Version
)(如果有这样的列,则为最后更新日期)并指示休眠使用此列进行版本更新。在这种情况下,如果我们更新 p1,会话刷新休眠将在更新前执行 select,查看版本信息不匹配(有人进入,更新记录)并抛出 StaleObject 异常