EntityManager.merge()可以插入新对象并更新现有对象。
为什么要使用persist()(它只能创建新对象)?
EntityManager.merge()可以插入新对象并更新现有对象。
为什么要使用persist()(它只能创建新对象)?
当前回答
我在我的实体上得到了lazyLoading异常,因为我试图访问一个会话中的惰性加载集合。
我要做的是在一个单独的请求中,从会话检索实体,然后尝试访问我的jsp页面中的一个集合,这是有问题的。
为了缓解这个问题,我在控制器中更新了相同的实体,并将其传递给我的jsp,尽管我想象当我在会话中重新保存时,它也可以通过SessionScope访问,而不会抛出一个LazyLoadingException,这是示例2的修改:
以下是我行之有效的方法:
// scenario 2 MY WAY
// tran starts
e = new MyEntity();
e = em.merge(e); // re-assign to the same entity "e"
//access e from jsp and it will work dandy!!
其他回答
我在我的实体上得到了lazyLoading异常,因为我试图访问一个会话中的惰性加载集合。
我要做的是在一个单独的请求中,从会话检索实体,然后尝试访问我的jsp页面中的一个集合,这是有问题的。
为了缓解这个问题,我在控制器中更新了相同的实体,并将其传递给我的jsp,尽管我想象当我在会话中重新保存时,它也可以通过SessionScope访问,而不会抛出一个LazyLoadingException,这是示例2的修改:
以下是我行之有效的方法:
// scenario 2 MY WAY
// tran starts
e = new MyEntity();
e = em.merge(e); // re-assign to the same entity "e"
//access e from jsp and it will work dandy!!
我注意到,当我使用em.merge时,每个INSERT都有一个SELECT语句,即使JPA没有为我生成字段——主键字段是我自己设置的UUID。我切换到em.persist(myEntityObject),然后只得到INSERT语句。
JPA规范说明了关于persist()的以下内容。
如果X是一个分离对象,则在持久化时可能会抛出EntityExistsException 操作被调用,或者EntityExistsException或另一个PersistenceException可能在刷新或提交时抛出。
因此,当对象不应该是分离对象时,使用persist()是合适的。您可能更喜欢让代码抛出PersistenceException,以便快速失败。
尽管规范不清楚,persist()可能会为对象设置@GeneratedValue @Id。但是merge()必须有一个已经生成的@Id对象。
场景X:
表:spititter(1),表:Spittles(许多)(Spittles是与FK:spitter_id关系的所有者)
这个场景的结果是节省:喷壶和两个喷壶就像被同一个喷壶拥有一样。
Spitter spitter=new Spitter();
Spittle spittle3=new Spittle();
spitter.setUsername("George");
spitter.setPassword("test1234");
spittle3.setSpittle("I love java 2");
spittle3.setSpitter(spitter);
dao.addSpittle(spittle3); // <--persist
Spittle spittle=new Spittle();
spittle.setSpittle("I love java");
spittle.setSpitter(spitter);
dao.saveSpittle(spittle); //<-- merge!!
场景Y:
这将拯救喷壶,将拯救2喷壶,但他们不会引用同一喷壶!
Spitter spitter=new Spitter();
Spittle spittle3=new Spittle();
spitter.setUsername("George");
spitter.setPassword("test1234");
spittle3.setSpittle("I love java 2");
spittle3.setSpitter(spitter);
dao.save(spittle3); // <--merge!!
Spittle spittle=new Spittle();
spittle.setSpittle("I love java");
spittle.setSpitter(spitter);
dao.saveSpittle(spittle); //<-- merge!!
持久化和合并是为了两个不同的目的(它们根本不是替代方案)。
(编辑以扩大差异信息)
坚持:
向数据库中插入一个新的寄存器 将对象附加到实体管理器。
走:
找到具有相同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是一个非常高级的编程,你不能假设这将是任何地方的情况。