我知道Session
是 Hibernate 使用的第一级缓存这一事实,一旦我们从session
检索实体,后续的get调用具有相同标识符的相同实体是从session
而非DB获取的,直到session
打开。 / p>
话虽如此,我怀疑hibernate如何将第一级缓存与DB同步?请考虑以下情况
//Lets say I have created the session
Session s1 = sessionFactory.getSession();
User u1 = s1.get(User.class, 1); //Getting User with ID=1
//s1 is not yet closed
//Lets say I create some other session
Session s2 = sessionFactory.getSession();
User u2 = s2.get(User.class, 1); //Getting User with ID=1
u2.setName("Abc"); // Changed a field
s2.save(u2); // Saved the changes to DB
s2.close(); //Closed the 2nd session
//Now when I once again retrieve User with ID=1 from s1, will I get updated User?
User u3 = s1.get(User.class, 1);// Here as per my understanding cache is used
所以我的问题是
u3
是从第一级缓存中提取的,u3
是否有更新值? session
是否与数据库同步?提前感谢您在此主题上花费的时间和精力
答案 0 :(得分:3)
您需要以s1
为u1
作为参数调用Session.evict(Object)
才能获得新的查询。或者,对于这种情况,您也可以在s1
上调用Session.clear()
以获得相同的效果。您也可以致电Session.refresh(Object object)
来刷新u1
的状态。
请注意,事务可能会花费不确定的时间(通常不会很长),以便其他客户端在提交后可以看到。对于使用不同连接的其他会话,可能无法立即看到更新。
答案 1 :(得分:3)
不,Hibernate没有做任何事情来将会话缓存中的实体状态与数据库同步,除非您明确请求它。
通常这不是问题,因为活动工作通常发生在事务中,并且事务内的操作不应该看到其他并发事务所做的更改(但细节依赖于隔离级别)。因此,在这种情况下,Hibernate的行为补充了事务隔离的典型语义。
还可能存在需要明确同步实体状态以反映在同一事务中进行的更改的情况。它可能是由批量更新查询或数据库触发器的执行引起的。在这种情况下,您需要通过调用refresh()
显式请求此类同步。
答案 2 :(得分:2)
第一级(会话级)缓存可确保加载持久实例的状态 一个交易与其他交易所做的更改隔离开来。
因此,当您在第一个事务中调用s2
时,s1.get(User.class, 1)
在另一个事务(T2)中所做的更改是不可见的,因为这次Hibernate将从中获取User
会话级缓存s1
。