Hibernate中persist()和merge()有什么区别?

问题

Hibernate中persist()和merge()有什么区别?

persist()可以创建UPDATE和INSERT查询,例如:

SessionFactory sef = cfg.buildSessionFactory();
Session session = sef.openSession();
A a=new A();
session.persist(a);
a.setName("Mario");
session.flush();

在这种情况下查询将会像这样生成:

Hibernate: insert into A (NAME, ID) values (?, ?)
Hibernate: update A set NAME=? where ID=?

sopersist()方法can生成an插入和更新。

现在用merge()

SessionFactory sef = cfg.buildSessionFactory();
Session session = sef.openSession();
Singer singer = new Singer();
singer.setName("Luciano Pavarotti");
session.merge(singer);
session.flush();

这是我在数据库中看到的:

SINGER_ID   SINGER_NAME
1           Ricky Martin
2           Madonna
3           Elvis Presley
4           Luciano Pavarotti

现在使用merge()更新记录

SessionFactory sef = cfg.buildSessionFactory();
Session session = sef.openSession();
Singer singer = new Singer();
singer.setId(2);
singer.setName("Luciano Pavarotti");
session.merge(singer);
session.flush();

这是我在数据库中看到的:

SINGER_ID   SINGER_NAME
1           Ricky Martin
2           Luciano Pavarotti
3           Elvis Presley

#1 热门回答(137 赞)

JPA specification包含对这些操作的语义的非常精确的描述,比javadoc更好:

应用于实体X的持久化操作的语义如下:如果X是新实体,则它将被管理。实体X将在事务提交时或之前或作为刷新操作的结果输入数据库。如果X是预先存在的托管实体,则persist操作会忽略它。但是,如果从X到这些其他实体的关系使用cascade = PERSIST或cascade = ALL注释元素值注释或使用等效的XML描述符元素指定,则持久化操作会级联到X引用的实体。如果X是已删除的实体,则它将被管理。如果X是一个分离的对象,则在调用persist操作时可能会抛出EntityExistsException,或者可能在flush或commit时抛出EntityExistsException或另一个PersistenceException。对于来自X的关系引用的所有实体Y,如果与Y的关系已使用级联元素值cascade = PERSIST或cascade = ALL进行注释,则将持久操作应用于Y.
应用于实体X的合并操作的语义如下:如果X是分离的实体,则将X的状态复制到相同标识的预先存在的管理实体实例X'或新的管理副本X'上创建了X.如果X是新的实体实例,则创建新的管理实体实例X',并且将X的状态复制到新的管理实体实例X'中。如果X是已删除的实体实例,则合并操作将抛出IllegalArgumentException(或者事务提交将失败)。如果X是托管实体,则合并操作会忽略它,但是,如果已使用级联元素值cascade = MERGE或cascade = ALL批注对这些关系进行批注,则合并操作将级联到由X关系引用的实体。对于具有级联元素值cascade = MERGE或cascade = ALL的X的关系引用的所有实体Y,Y被递归地合并为Y'。对于由X引用的所有这样的Y,X'被设置为引用Y'。 (注意,如果管理X,则X与X'是同一个对象。)如果X是合并到X'的实体,并且引用另一个实体Y,其中未指定cascade = MERGE或cascade = ALL,则导航来自X'的相同关联产生对具有与Y相同的持久标识的被管理对象Y'的引用。


#2 热门回答(16 赞)

这来自JPA。以一种非常简单的方式:

persist(entity)应该与全新的实体一起使用,将它们添加到DB中(如果实体已经存在于DB中,则会抛出EntityExistsException)。

应该使用merge(entity),如果实体被分离并被更改,则将实体放回到持久化上下文。


#3 热门回答(8 赞)

应该仅在新实体上调用Persist,而merge用于重新附加分离的实体。

如果你使用的是指定的生成器using merge instead of persist can cause a redundant SQL statement,则会影响性能。

此外,calling merge for managed entities也是一个错误,因为管理实体由Hibernate自动管理,并且它们的状态与dirty checking mechanismuponflushing the Persistence Context的数据库记录同步。