JPA:合并和持久化上下文
JPA: merge and persistence context
我有以下代码在使用 class:
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。
JPA 2.0 规范的以下摘录应该给出解释:
The merge operation allows for the propagation of state from detached entities onto persistent entities
managed by the entity manager.
The semantics of the merge operation applied to an entity X are as follows:
• If X is a detached entity, the state of X is copied onto a pre-existing managed entity instance X' of the same identity or a new managed copy X' of X is created.
• If X is a new entity instance, a new managed entity instance X' is created and the state of X is copied into the new managed entity instance X'.
• If X is a removed entity instance, an IllegalArgumentException will be thrown by the merge operation (or the transaction commit will fail).
• If X is a managed entity, it is ignored by the merge operation, however, the merge operation is cascaded to entities referenced by relationships from X if these relationships have been annotated with the cascade element value cascade=MERGE or cascade=ALL annotation.
• For all entities Y referenced by relationships from X having the cascade element value cascade=MERGE or cascade=ALL, Y is merged recursively as Y'. For all such Y referenced by X, X' is set to reference Y'. (Note that if X is managed then X is the same object as
X'.)
• If X is an entity merged to X', with a reference to another entity Y, where cascade=MERGE or cascade=ALL is not specified, then navigation of the same association from X' yields a reference to a managed object Y' with the same persistent identity as Y.
根据规范,您的 Entity
应该保存到数据库中。但是因为您的更改在两种情况下都是相同的(lalala
和 100
)(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()
,这次只为ID=101的实体修改了name
属性:
@Test
public void createEmployee() {
Employee emp = new Employee();
emp.setName("Test2");
emp.setSalary(1000);
emp.setId(101);
tx.begin();
em.merge(emp);
tx.commit();
}
我有以下代码在使用 class:
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。
JPA 2.0 规范的以下摘录应该给出解释:
The merge operation allows for the propagation of state from detached entities onto persistent entities managed by the entity manager.
The semantics of the merge operation applied to an entity X are as follows:
• If X is a detached entity, the state of X is copied onto a pre-existing managed entity instance X' of the same identity or a new managed copy X' of X is created.
• If X is a new entity instance, a new managed entity instance X' is created and the state of X is copied into the new managed entity instance X'.
• If X is a removed entity instance, an IllegalArgumentException will be thrown by the merge operation (or the transaction commit will fail).
• If X is a managed entity, it is ignored by the merge operation, however, the merge operation is cascaded to entities referenced by relationships from X if these relationships have been annotated with the cascade element value cascade=MERGE or cascade=ALL annotation.
• For all entities Y referenced by relationships from X having the cascade element value cascade=MERGE or cascade=ALL, Y is merged recursively as Y'. For all such Y referenced by X, X' is set to reference Y'. (Note that if X is managed then X is the same object as X'.)
• If X is an entity merged to X', with a reference to another entity Y, where cascade=MERGE or cascade=ALL is not specified, then navigation of the same association from X' yields a reference to a managed object Y' with the same persistent identity as Y.
根据规范,您的 Entity
应该保存到数据库中。但是因为您的更改在两种情况下都是相同的(lalala
和 100
)(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()
,这次只为ID=101的实体修改了name
属性:@Test public void createEmployee() { Employee emp = new Employee(); emp.setName("Test2"); emp.setSalary(1000); emp.setId(101); tx.begin(); em.merge(emp); tx.commit(); }