Hibernate持久对象行为

时间:2011-11-18 21:52:03

标签: java hibernate persistence

我试图了解Hibernate中对象的不同状态。我尝试了以下操作,无法找到所显示行为的解释。有人可以帮忙吗?

以下是我要做的事情:在Employee表中插入一条新记录(empId是主键)。在同一事务中,更新新添加的记录(使用查询,修改empName)。然后当我检查持久对象的empName属性时,它继续显示旧的empName值。作为一个持久对象,我希望它能反映数据库中所做的更改。我不明白为什么没有。 (除了将“hibernate.hbm2ddl.auto”属性设置为update之外,我的hibernate配置文件都将所有设置为默认值) 但是,在进行更新之后,当我使用getEmpName返回的值设置持久对象的empName(由sysout显示为旧的empName值)时,表中的最终数据显示新的empName值(即我使用更新的值) HQL)。请参阅以下代码:

Transaction tx = session.getTransaction();
    tx.begin();

    Employee e1 = new Employee();
    e1.setEmpId(1);
    e1.setEmpName("Jack");
    e1.setEmpAge(25);
    session.save(e1);
    System.out.println("before: "+e1.getEmpName()); //prints Jack
    session.createQuery("update Employee set empName = \'Jack_new\' where id=1").executeUpdate();
    System.out.println("after: "+e1.getEmpName()); //prints Jack
    e1.setEmpName(e1.getEmpName()); //should update database
    tx.commit(); //sets empName value to Jack_new, as seen in table
    System.out.println("last: "+e1.getEmpName()); //prints Jack

2 个答案:

答案 0 :(得分:5)

来自the hibernate documentation

  

直接在数据库中操作数据(使用SQL数据   操作语言(DML)语句:INSERT,UPDATE,DELETE)   不会影响记忆中​​的状态。

当您使用以下直接DML进行更新时,

session.createQuery("update Employee set empName = \'Jack_new\' where id=1").executeUpdate();

它将绕过Hibernate持久化上下文(以及所有缓存)。因此,虽然empName实际上是在DB中更新到Jack_new,但它在持久化上下文中的实例仍保留旧值。

您可以使用session.refresh(e1);从基础数据库重新读取e1的值,以便将e1.empName刷新为Jack_new

通常,我们不会手动编写UPDATE语句来执行update。将更新的值设置为持久化实例的属性。在刷新期间,hibernate将执行脏检查,自动生成并发出相应的更新SQL以更新这些脏实例。


(回复评论):

  

但是,在执行tx.commit()之前,我将e1.empName设置为old   value(即e1.getEmpName()返回的值)。仍然是最终的   在数据库中看到的值是新值。?

/**e1 become persisted after save()**/
 session.save(e1);

/**e1.empName is updated to new value in the DB , but as the direct DML
 will not affect in-memory state , e1.empName in the java side 
 still keeps the old value***/
 session.createQuery("update Employee set empName = \'Jack_new\' where id=1").executeUpdate();

/** As you only set `e1.empName` to its original value , the values of `e1` do 
not have any changes. Thus , during the flushing (which occurs at the moment 
before `commit()`) , hibernate will consider  that `e1` is not dirty  and 
hence no update SQL will be generated and issued to update e1 . 
***/
e1.setEmpName(e1.getEmpName()); 

因此,结果是Jack_new保存在数据库中。

答案 1 :(得分:1)

你正在对数据库执行直接查询,改变hibernate后面的字段值。当你这样做时,你的对象不会神奇地改变它的保存值,这是原始名称。所以当你做“e1.setEmpName(e1.getEmpName());”您将名称设置回原始值。