集群环境中的Hibernate会话缓存行为?

时间:2018-07-10 16:51:02

标签: java hibernate hibernate-session

在我参加的一次采访中,我被问到以下问题-

  

比方说,我们有多集群的应用程序服务器,每个服务器都创建了自己的SessionFactory(指向相同的单个DB)。一台服务器检索一条记录[ID为1的人],该记录在仍处于打开状态的会话(s1)中缓存该记录。

     

同时,另一台服务器打开另一个会话(s2)并更新ID = 1的Person记录。现在,在s1中缓存的Person记录会怎样?这会是陈旧的记录吗?

我创建了一个小程序来模拟单个JVM上的场景。令我惊讶的是,尽管从同一class Frange(object): def __init__(self, value, end=None, step=1.0): if end is None: self.start, self.end = 0.0, value self.step = step else: self.start = value self.end = end self.step = step def __iter__(self): return self def __next__(self): if self.start < self.end: return self.start for n in Frange(0.5, 2.5, 0.5): print(n) 创建了2个会话,会话缓存仍保留了过时的数据。甚至SessionFactory也无济于事。

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); 是否会使缓存无效?

1 个答案:

答案 0 :(得分:1)

是的,p1将是陈旧的记录。如果更新p1,则在会话刷新或会话s1的事务提交时,p1将覆盖p2的更新。

为防止这种情况,您可以使用乐观锁定 g。指定版本号(在Java源代码中为@Version)(如果有这样的列,则指定为last-updated-date),并指示hibernate使用此列进行版本更新。在这种情况下,如果我们更新p1,则在会话刷新休眠状态下,hibernate将在更新之前执行一次选择,看到版本信息不匹配(有人进来,在中间并更新了记录),并抛出了StaleObject异常