在Hibernate中比较两个对象的问题

时间:2013-12-14 00:16:59

标签: java spring hibernate transactions jpa-2.0

我有两种方法。

@Service
@Transactional
public class MyService {

    void myMethod() {
       Entity e1 = dao.get(1);
       e1.setName("NEW ENTITY NAME");
       save(e1);
    }

    void save(Entity e) {
      Entity oldEntity = dao.get(1);
      oldEntity.getName().equals(e.getName()) // TRUE. Why? 
    }

}

但是在方法save中,实体没有区别,即旧实体和更新实体都具有相同的字段值("NEW ENTITY NAME")。 Spring中的事务配置正确,默认传播是Propagation.REQUIRED

3 个答案:

答案 0 :(得分:2)

同样见answer,这实际上是正常行为。第一个dao.get(1)检索具有数据库密钥1的实体,并且附加到会话。

执行第二个dao.get(1)时,会话仍然打开,因此Hibernate不会再次查询数据库,而是返回已经附加到会话的引用。

从Hibernate的角度来看,这个表只有一个数据库对象,键1,并且它已经拥有对它的最新内存版本的引用,所以Hibernate也可以返回它并备用一个查询。

为了比较内存中的持久对象与它的数据库版本,一种方法是首先加载对象并在调用对象上的setter之前进行比较。

另一种方法是首先使用session.evict()从会话中分离对象,然后从数据库加载对象。

这将确保数据的数据库版本被加载到会话中。然后可以在现在分离的被驱逐对象和新加载的对象之间进行比较。

如果您不想使用较新的数据替换数据库版本,请在被驱逐的对象上调用session.merge()。

答案 1 :(得分:1)

如果我没记错的话,Hibernate在会话级别有一个缓存系统,如果检索到某个实体,它将被缓存并返回同一个Session内同一实体的任何请求。因此,您要比较同一个对象。您可以通过

确认
oldEntity == e

What are First and Second Level caching in Hibernate?

答案 2 :(得分:0)

如果要使用较新的数据替换数据库版本,请在被驱逐的对象上调用session.merge()