5

我知道HibernateSession使用的是一级缓存这一事实,一旦我们从 中检索实体,随后对具有相同标识符的同一实体的 get 调用将从DB 而不是 DB中获取,直到Open为止。sessionsessionsession

话虽如此,我对hibernate如何将一级缓存与数据库同步有疑问?考虑以下场景

//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与数据库同步?

预先感谢您在此线程上的时间和精力

4

3 回答 3

3

不,Hibernate 不会做任何事情来将会话缓存中实体的状态与数据库同步,除非您明确请求它。

通常这不是问题,因为活动工作通常发生在事务内部,并且事务内部的操作不应该看到其他并发事务所做的更改(但细节取决于隔离级别)。因此,在这种情况下,Hibernate 的行为补充了事务隔离的典型语义。

在某些情况下,实体的状态需要显式同步以反映在同一事务中所做的更改。它可能是由批量更新查询或执行数据库触发器引起的。在这种情况下,您需要通过调用显式请求此类同步refresh()

于 2013-09-10T14:54:17.047 回答
3

您需要调用Session.evict(Object)withs1作为u1参数才能获得新的查找。或者,对于这种情况,您也可以调用Session.clear()s1获得相同的效果。您也可以调用Session.refresh(Object object)来刷新状态u1

请注意,事务在提交后可能需要一段未定义的时间(通常不会很长)才能被其他客户端看到。使用不同连接的其他会话可能不会立即看到更新。

于 2013-09-10T14:50:22.057 回答
2

第一级(会话级)缓存确保一个事务加载的持久实例的状态与其他事务所做的更改隔离。

因此,当您在第一个事务中调用时,在不同事务(T2)中所做的更改s2是不可见s1.get(User.class, 1)的,因为这次 Hibernate 将从User会话级缓存中获取s1

于 2013-09-10T15:04:45.487 回答