2016-05-13 48 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(); 
    }