EntityManager.merge()可以插入新对象并更新现有对象。
为什么要使用persist()(它只能创建新对象)?
EntityManager.merge()可以插入新对象并更新现有对象。
为什么要使用persist()(它只能创建新对象)?
当前回答
merge和persist之间还有一些区别(我将再次列举已经在这里发布的区别):
D1。Merge不会使传递的实体受管理,而是返回另一个受管理的实例。在另一边持久化将使传递的实体被管理:
//MERGE: passedEntity remains unmanaged, but newEntity will be managed
Entity newEntity = em.merge(passedEntity);
//PERSIST: passedEntity will be managed after this
em.persist(passedEntity);
D2。如果你删除了一个实体,然后决定持久化该实体,你只能使用persist()来做,因为merge会抛出一个IllegalArgumentException。
D3。如果您决定手动处理您的id(例如通过使用uuid),则合并 operation将触发后续的SELECT查询,以查找具有该ID的存在实体,而persist可能不需要这些查询。
D4。有些情况下,您只是不相信调用您的代码的代码,为了确保没有数据被更新,而是被插入,您必须使用持久化。
其他回答
通过回答,有一些关于“Cascade”和id生成的细节缺失。看到问题
此外,值得一提的是,您可以为合并和持久化使用单独的Cascade注释:Cascade。合并和级联。PERSIST将根据使用的方法进行处理。
规格是你的朋友;)
持久化和合并是为了两个不同的目的(它们根本不是替代方案)。
(编辑以扩大差异信息)
坚持:
向数据库中插入一个新的寄存器 将对象附加到实体管理器。
走:
找到具有相同id的附加对象并更新它。 如果存在,则更新并返回已附加的对象。 如果不存在,则将新寄存器插入数据库。
persist()效率:
在向数据库插入新寄存器时,它可能比merge()更有效。 它不会复制原始对象。
persist()的语义:
它确保您是在插入而不是错误地更新。
例子:
{
AnyEntity newEntity;
AnyEntity nonAttachedEntity;
AnyEntity attachedEntity;
// Create a new entity and persist it
newEntity = new AnyEntity();
em.persist(newEntity);
// Save 1 to the database at next flush
newEntity.setValue(1);
// Create a new entity with the same Id than the persisted one.
AnyEntity nonAttachedEntity = new AnyEntity();
nonAttachedEntity.setId(newEntity.getId());
// Save 2 to the database at next flush instead of 1!!!
nonAttachedEntity.setValue(2);
attachedEntity = em.merge(nonAttachedEntity);
// This condition returns true
// merge has found the already attached object (newEntity) and returns it.
if(attachedEntity==newEntity) {
System.out.print("They are the same object!");
}
// Set 3 to value
attachedEntity.setValue(3);
// Really, now both are the same object. Prints 3
System.out.println(newEntity.getValue());
// Modify the un attached object has no effect to the entity manager
// nor to the other objects
nonAttachedEntity.setValue(42);
}
这种方法对于实体管理器中的任何寄存器只存在一个附加对象。
对于带id的实体,Merge()是这样的:
AnyEntity myMerge(AnyEntity entityToSave) {
AnyEntity attached = em.find(AnyEntity.class, entityToSave.getId());
if(attached==null) {
attached = new AnyEntity();
em.persist(attached);
}
BeanUtils.copyProperties(attached, entityToSave);
return attached;
}
虽然如果连接到MySQL merge()可以像persist()一样有效,使用一个调用INSERT和ON DUPLICATE KEY UPDATE选项,JPA是一个非常高级的编程,你不能假设这将是任何地方的情况。
这两种方法都会将实体添加到PersistenceContext中,区别在于之后如何处理实体。
Persist获取一个实体实例,将其添加到上下文中,并使该实例被管理(即将跟踪实体的未来更新)。
Merge返回与状态合并的托管实例。它确实返回存在于PersistenceContext中的内容或创建实体的新实例。在任何情况下,它都会从提供的实体复制状态,并返回一个托管副本。传入的实例不会被管理(你所做的任何更改都不会成为事务的一部分——除非你再次调用merge)。不过您可以使用返回的实例(托管实例)。
也许一个代码示例会有所帮助。
MyEntity e = new MyEntity();
// scenario 1
// tran starts
em.persist(e);
e.setSomeField(someValue);
// tran ends, and the row for someField is updated in the database
// scenario 2
// tran starts
e = new MyEntity();
em.merge(e);
e.setSomeField(anotherValue);
// tran ends but the row for someField is not updated in the database
// (you made the changes *after* merging)
// scenario 3
// tran starts
e = new MyEntity();
MyEntity e2 = em.merge(e);
e2.setSomeField(anotherValue);
// tran ends and the row for someField is updated
// (the changes were made to e2, not e)
场景1和3大致相同,但在某些情况下,您可能希望使用场景2。
merge和persist之间还有一些区别(我将再次列举已经在这里发布的区别):
D1。Merge不会使传递的实体受管理,而是返回另一个受管理的实例。在另一边持久化将使传递的实体被管理:
//MERGE: passedEntity remains unmanaged, but newEntity will be managed
Entity newEntity = em.merge(passedEntity);
//PERSIST: passedEntity will be managed after this
em.persist(passedEntity);
D2。如果你删除了一个实体,然后决定持久化该实体,你只能使用persist()来做,因为merge会抛出一个IllegalArgumentException。
D3。如果您决定手动处理您的id(例如通过使用uuid),则合并 operation将触发后续的SELECT查询,以查找具有该ID的存在实体,而persist可能不需要这些查询。
D4。有些情况下,您只是不相信调用您的代码的代码,为了确保没有数据被更新,而是被插入,您必须使用持久化。
Merge不会更新传递的实体,除非该实体被管理。即使实体ID被设置为一个现有的DB记录,一个新的记录将在数据库中创建。