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

2022-08-31 08:31:24

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

答案 1

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

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

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

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

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

  • 如果 X 是分离的对象,则在调用持久操作时可能会引发 ,或者在刷新或提交时可能会引发 或 另一个对象。EntityExistsExceptionEntityExistsExceptionPersistenceException

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


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

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

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

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

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

  • 对于所有实体 Y 由具有级联元素值的 X 或 的关系引用,Y 以递归方式合并为 Y'。对于 X 引用的所有此类 Y,X' 设置为引用 Y'。(请注意,如果 X 是托管的,则 X 与 X' 是同一对象。cascade=MERGEcascade=ALL

  • 如果 X 是合并到 X' 的实体,并且引用了另一个实体 Y,其中未指定 或 未指定,则从 X' 导航相同的关联将生成对托管对象 Y' 的引用,该对象具有与 Y 相同的持久标识。cascade=MERGEcascade=ALL


答案 2

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

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

  • merge(entity)应该使用,以便在实体分离并已更改时将实体放回持久性上下文。


推荐