2011-11-18 84 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