2011-11-18 86 views
0

我试图了解Hibernate中对象的不同状态。我尝试了以下方法,但找不到所示行为的解释。谁能帮忙?Hibernate持久对象行为

这是我正在做的事情:在Employee表中插入一条新记录(empId是主键)。在同一个事务中,更新新添加的记录(使用查询,修改empName)。然后当我检查持久对象的empName属性时,它继续显示旧的empName值。作为一个持久对象,我期望它能够反映数据库中所做的更改。我不明白为什么它没有。 (我的hibernate配置文件除了“hibernate.hbm2ddl.auto”属性被设置为更新之外,其他都设置为默认值) 但是,在更新之后,当我设置持久对象的empName时,getEmpName返回值(显示为旧的empName值由sysout),表中的最终数据显示新的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 

回答

5

the hibernate documentation

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

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

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

它会绕过Hibernate持久化上下文(和所有的高速缓存)。所以,尽管empName实际上在数据库中更新为Jack_new,但它在持久化上下文中的实例仍旧保留旧值。

可以使用底层数据库,使得e1.empName将被刷新到Jack_newsession.refresh(e1);重新读取为e1值。

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


(回复评论):

然而,只是在做tx.commit()我设置e1.empName老 值(即由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保存在数据库中。

+0

感谢您的意见德米特里和肯。帮助我了解了大部分问题。但是,在做tx.commit()之前,我将e1.empName设置为旧值(即e1.getEmpName()返回的值)。仍然在数据库中看到的最终值是新值。 – Leo

+0

不客气,请参阅我的更新PLZ –

+0

谢谢。这使得一切都清晰可见。 – Leo

1

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

+0

谢谢。但是,在做tx.commit()之前,我正在设置e1。empName为旧值(即由e1.getEmpName()返回的值)。仍然在数据库中看到的最终值是新值。 – Leo