在 JPA 和 Hibernate 中,存储()和合并()之间有什么区别?

在 Hibernate 中,存储()和合并()有什么区别?

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
178852 次浏览

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

< strong > 的语义仍然存在 应用于实体 X 的 如下:

  • 如果 X 是一个新实体,则 实体 X 将成为 输入数据库 事务提交或由于 冲水操作

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

  • 如果 X 是一个被移除的实体, 它被管理

  • 如果 X 是 分离的物体 可能抛出 EntityExistsException 调用持久化操作时, 或者 EntityExistsException 另一个 PersistenceException可能是 在刷新或提交时抛出

  • 为了 引用的所有实体 Y 关系从 X,如果 与 Y 的关系已被注释 与级联元素值 cascade=PERSISTcascade=ALL 对 Y 进行持续操作


合并操作的语义 适用于实体 X 的情况如下:

  • 如果 X 是一个独立的实体,则状态 复制到已存在的 相同的托管实体实例 X’ 身分证明文件或 X 的新托管副本 X’ 被创建。

  • 如果 X 是一个新的实体 一个新的托管实体 实例 X’被创建,并且状态 复制到新的托管 实体实例 X’.

  • 如果 X 是 移除的实体实例 IllegalArgumentException会是 由合并操作(或 事务提交将失败)

  • 是托管实体,则 合并操作,但是 合并操作级联到 关系引用的实体 如果这些关系 被注释为瀑布 元素值 cascade=MERGEcascade=ALL注释
  • 为了所有人 关系引用的实体 Y 有级联元素的 X 值 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 中已经存在实体,将抛出 EntityISTsException)。

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

Perst 应该只在新实体上调用,而 merge意味着重新连接分离的实体。

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

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

最重要的区别在于:

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

  • 但是对于 merge方法,在持久化上下文中已经管理的实体将被新实体替换(简单地说,它将被更新) ,然后返回此更新实体的一个副本。(因此,从现在开始,如果您希望在持久化上下文中反映您的更改,就应该对这个返回的实体进行任何更改)