2016-05-13 47 views
2

我在服務類下面的代碼:JPA:合併和持久化上下文

public void updateEntity(Entity e){ 
    EntityManager em=entityManagerFactory.createEntityManager(); 
    em.getTransaction().begin(); 
    em.merge(e); 
    em.getTransaction().commit(); 
    em.close(); 
} 

public Entity readEntity(int id){ 
    EntityManager em=entityManagerFactory.createEntityManager(); 
    Entity result=em.find(Entity.class, id); 
    em.close(); 
    return result; 
} 

請注意,在這兩種功能的實體管理器(持久化上下文我的理解)關閉。

所以,當我做的:

Entity entity=service.readEntity(100); 
entity.setXxx("lalala"); 
service.updateEntity(entity); 

一切工作的需要,我在生成SQL的變化只有一個字段日誌中看到。 但是當我做:

Entity entity=new Entity(100); 
entity.setXxx("lalala"); 
service.updateEntity(entity); 

的更改不會寫入到數據庫。請解釋原因。我使用EclipseLink。

+0

當你有一個新的實體時使用em.persist。 –

+0

如果您在第二次測試之前從第一次測試中運行代碼,那麼setXxx(「lalala」)調用不會真的改變任何內容。查找調用後,在em.merge(e);返回的實體中檢查實體中的值。對於調試,您也可以在合併調用之前嘗試em.find調用並檢查返回的對象中的值 - 如果對象已經存在,則不應該改變任何內容,因爲EclipseLink在內部也會執行相同的操作。 – Chris

回答

3

從JPA 2.0規範以下提取物應該給出一個解釋:

合併操作允許狀態從分離實體傳播到由實體管理器管理持久實體 。

應用到實體X合併操作的語義如下:

•如果X是一個分離的實體,X的狀態被複制到預先存在的管理實體實例的相同的X」 X的身份或新託管副本X'被創建。

•如果X是新的實體實例,則會創建一個新的託管實體實例X',並將X的狀態複製到新的託管實體實例X'中。

•如果X是已刪除的實體實例,合併操作將拋出IllegalArgumentException異常(否則事務提交將失敗)。

•如果X是受管實體,合併操作會忽略它,但是,合併操作級聯到由X關係引用的實體,如果這些關係已使用級聯元素值cascade = MERGE或級聯=所有註釋。

•對於由具有級聯元素值級聯= MERGE或級聯= ALL的X的關係引用的所有實體Y,Y以遞歸方式合併爲Y'。對於由X引用的所有這樣的Y,將X'設置爲引用Y'。 (請注意,如果管理X,則X與 X'是同一個對象。)

•如果X是合併到X'的實體,並引用另一個實體Y,其中cascade = MERGE或cascade = ALL未指定,那麼從X相同的關聯的導航「產生的管理對象Y上引用」爲Y.

用相同的持久化標識根據您的Entity應保存到數據庫中的規範。但是因爲你的變化是在兩種情況下相同(lalala100)(find()然後merge()營造然後merge()),可能是你有沒有注意到在數據庫中的變化。 我已經測試了以下的情況下,一切都按預期工作:

  • 我創建了一個新的實體,合併後如下(這在數據庫中創建與ID = 101的新條目):

    @Test 
    public void createEmployee() { 
        Employee emp = new Employee(); 
        emp.setName("Test"); 
        emp.setSalary(1000); 
        tx.begin(); 
        em.merge(emp); 
        tx.commit(); 
    } 
    
  • 然後我做了以下和調用merge(),這時候只有name屬性被修改用於與ID的實體= 101:

    @Test 
    public void createEmployee() { 
        Employee emp = new Employee(); 
        emp.setName("Test2"); 
        emp.setSalary(1000); 
        emp.setId(101); 
        tx.begin(); 
        em.merge(emp); 
        tx.commit(); 
    }