繁体   English   中英

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

[英]What is the difference between persist() and merge() in JPA and Hibernate?

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=?

所以persist()方法可以生成一个插入和一个更新。

现在使用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

JPA 规范包含对这些操作语义的非常精确的描述,比 javadoc 中的要好:

应用于实体 X 的持久操作的语义如下:

  • 如果 X 是一个新实体,它将成为托管。 实体 X 将在事务提交时或之前或作为刷新操作的结果输入到数据库中。

  • 如果 X 是预先存在的受管实体,则持久操作将忽略它。 但是,如果从 X 到这些其他实体的关系使用cascade=PERSISTcascade=ALL注释元素值注释或使用等效的 XML 描述符元素指定,则持久操作级联到由 X 引用的实体。

  • 如果 X 是已删除的实体,则它变为托管的。

  • 如果X是一个分离的目的, EntityExistsException当persist操作被调用时,或者可能抛出EntityExistsException或另一个PersistenceException可以在冲洗被抛出或提交时间。

  • 对于由来自 X 的关系引用的所有实体 Y,如果与 Y 的关系已使用级联元素值cascade=PERSISTcascade=ALL进行注释,则对 Y 应用持久操作。


应用于实体 X 的合并操作的语义如下:

  • 如果 X 是分离的实体,则 X 的状态被复制到具有相同身份的预先存在的受管实体实例 X' 上,或者创建 X 的新受管副本 X'。

  • 如果 X 是新的实体实例,则创建新的受管实体实例 X',并将 X 的状态复制到新的受管实体实例 X'。

  • 如果 X 是已删除的实体实例,则合并操作将抛出IllegalArgumentException (否则事务提交将失败)。

  • 如果 X 是受管实体,则合并操作将忽略它,但是,如果这些关系已使用级联元素值cascade=MERGEcascade=ALL注释,则合并操作级联到由来自 X 的关系引用的实体。

  • 对于由来自 X 的关系引用的所有实体 Y 具有级联元素值cascade=MERGEcascade=ALL ,Y 被递归合并为 Y'。 对于 X 引用的所有此类 Y,X' 设置为引用 Y'。 (请注意,如果 X 是被管理的,那么 X 与 X' 是同一个对象。)

  • 如果 X 是合并到 X' 的实体,并引用另一个实体 Y,其中未指定cascade=MERGEcascade=ALL ,则从 X' 导航相同关联会产生对托管对象 Y' 的引用与 Y 相同的持久身份。

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

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

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

Persist 应该只在新实体上调用,而merge意味着重新附加分离的实体。

如果您使用指定的生成器,使用merge而不是persist可能会导致冗余的 SQL 语句。

此外,为托管实体调用合并也是一个错误,因为托管实体由 Hibernate 自动管理,并且它们的状态在刷新持久性上下文时通过脏检查机制与数据库记录同步。

最重要的区别是:

  • persist方法的情况下,如果要在持久化上下文中管理的实体已经存在于持久化上下文中,则忽略新的实体。 (什么都没有发生)

  • 但是在merge方法的情况下,已经在持久化上下文中管理的实体将被新实体(更新)替换,并且这个更新实体的副本将返回。 (从现在开始,如果您想在持久性上下文中反映您的更改,则应对此返回的实体进行任何更改)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM