【问题标题】:Hibernate persistent object behavior休眠持久对象行为
【发布时间】:2011-11-18 21:52:03
【问题描述】:

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

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

【问题讨论】:

    标签: java hibernate persistence


    【解决方案1】:

    来自the hibernate documentation

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

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

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

    它将绕过 Hibernate 持久性上下文(和所有缓存)。所以,虽然empName实际上在数据库中更新为Jack_new,但它在持久化上下文中的实例仍然保持旧值。

    您可以使用session.refresh(e1); 从底层数据库中重新读取e1 的值,这样e1.empName 将被刷新为Jack_new

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


    (回复评论):

    但是,就在执行 tx.commit() 之前,我将 e1.empName 设置为 old 值(即 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 保存在数据库中。

    【讨论】:

    • 感谢您的 cmets Dmitry 和 Ken。帮助我理解了大部分问题。但是,就在执行 tx.commit() 之前,我将 e1.empName 设置为旧值(即 e1.getEmpName() 返回的值)。在数据库中看到的最终值仍然是新值。?
    【解决方案2】:

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

    【讨论】:

    • 谢谢。但是,就在执行 tx.commit() 之前,我将 e1.empName 设置为旧值(即 e1.getEmpName() 返回的值)。仍然在数据库中看到的最终值是新值。?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多