Hibernate中不同的保存方法有什么区别?

java hibernate persistence

107633 观看

10回复

43289 作者的声誉

Hibernate有一些方法,以这种或那种方式,获取对象并将其放入数据库。它们之间有什么区别,什么时候使用哪个,为什么不存在一个知道何时使用什么的智能方法?

到目前为止我发现的方法是:

  • save()
  • update()
  • saveOrUpdate()
  • saveOrUpdateCopy()
  • merge()
  • persist()
作者: Henrik Paul 的来源 发布者: 2008 年 10 月 2 日

回应 (10)


113

4800 作者的声誉

决定

这是我对这些方法的理解。主要是这些是基于API,但我没有在实践中使用所有这些。

saveOrUpdate 根据某些检查调用保存或更新。例如,如果不存在标识符,则调用save。否则调用更新。

保存 持有实体。如果不存在标识符,将分配标识符。如果有的话,它实质上是在进行更新。返回生成的实体ID。

update 尝试使用现有标识符持久保存实体。如果不存在标识符,我认为会抛出异常。

saveOrUpdateCopy 这是不推荐使用的,不应再使用。而是......

合并 现在这是我的知识开始蹒跚的地方。这里重要的是瞬态,分离和持久实体之间的区别。有关对象状态的更多信息,请查看此处。通过保存和更新,您将处理持久对象。它们链接到一个Session,因此Hibernate知道发生了什么变化。但是当你有一个瞬态对象时,就没有涉及会话。在这些情况下,您需要使用merge进行更新并保留以进行保存。

persist 如上所述,这用于瞬态对象。它不会返回生成的ID。

作者: Lee Theobald 发布者: 02.10.2008 08:32

65

7229 作者的声誉

  • 有关持久化和保存之间细微差别的解释,请参阅Hibernate论坛。看起来不同的是INSERT语句最终执行的时间。由于save确实返回了标识符,因此无论事务的状态如何(通常都是坏事),INSERT语句都必须立即执行。Persist不会为了分配标识符而在当前运行的事务之外执行任何语句。保存/保持两者都可以处理瞬态实例,即尚未分配标识符的实例,因此不会保存在数据库中。

  • 更新合并都适用于分离的实例,即在DB中具有相应条目但当前未附加到会话(或由其管理)的实例。它们之间的区别是传递给函数的实例会发生什么。update尝试重新附加实例,这意味着现在可能没有附加到Session的持久实体的其他实例,否则抛出异常。但是,merge只是将所有值复制到Session中的持久化实例(如果当前未加载,将加载它)。输入对象不会更改。因此,merge更新更通用,但可能会使用更多资源。

作者: jrudolph 发布者: 02.10.2008 09:05

2

1319 作者的声誉

请注意,如果在分离对象上调用更新,则无论是否更改了对象,数据库中都将始终进行更新。如果它不是你想要的,你应该使用带有LockMode.None的Session.lock()。

仅当对象在当前会话范围之外更改时(处于分离模式时),才应调用update。

作者: bernardn 发布者: 03.10.2008 12:13

5

59 作者的声誉

实际上,hibernate save()persist()方法之间的区别取决于我们正在使用的生成器类。

如果我们的生成器类被分配,那么save()persist(方法之间没有区别。因为生成器'已分配'意味着,作为程序员,我们需要将主键值保存在数据库中[希望您知道这个生成器概念]如果不是指定的生成器类,假设我们的生成器类名称是递增均值hibernate it self会将主键id值分配到数据库中[除了分配的生成器,hibernate只用于照顾主键id值记住],所以在这种情况下如果我们调用save()或者persist()方法那么它会将记录插入正常数据库但是听到的是, save()方法可以返回由hibernate生成的主键id值,我们可以看到它

long s = session.save(k);

在同样的情况下,persist()永远不会给客户任何价值。

作者: Hari Krishna 发布者: 11.04.2012 05:45

1

76 作者的声誉

以下答案都不对。所有这些方法似乎都是相似的,但在实践中做的绝对不同。很难给出简短的评论。最好提供有关这些方法的完整文档的链接:http//docs.jboss.org/hibernate/core/3.6/reference/en-US/html/objectstate.html

作者: Anton Popovich 发布者: 26.10.2012 10:38

12

532 作者的声誉

此链接以良好的方式解释:

http://www.stevideter.com/2008/12/07/saveorupdate-versus-merge-in-hibernate/

我们都遇到了很少遇到的问题,当我们再次看到它们时,我们知道我们已经解决了这个问题,但却记不起来了。

在Hibernate中使用Session.saveOrUpdate()时抛出的NonUniqueObjectException是我的一个。我将为复杂的应用程序添加新功能。我所有的单元测试都运行良好。然后在测试UI时,尝试保存一个对象,我开始得到一个异常,消息“具有相同标识符值的另一个对象已经与会话相关联。”这是来自Java Persistence with Hibernate的一些示例代码。

            Session session = sessionFactory1.openSession();
            Transaction tx = session.beginTransaction();
            Item item = (Item) session.get(Item.class, new Long(1234));
            tx.commit();
            session.close(); // end of first session, item is detached

            item.getId(); // The database identity is "1234"
            item.setDescription("my new description");
            Session session2 = sessionFactory.openSession();
            Transaction tx2 = session2.beginTransaction();
            Item item2 = (Item) session2.get(Item.class, new Long(1234));
            session2.update(item); // Throws NonUniqueObjectException
            tx2.commit();
            session2.close();

要了解此异常的原因,了解分离的对象以及在分离的对象上调用saveOrUpdate()(或只是update())时会发生什么很重要。

当我们关闭一个单独的Hibernate Session时,我们正在处理的持久对象被分离。这意味着数据仍然在应用程序的内存中,但Hibernate不再负责跟踪对象的更改。

如果我们然后修改我们的分离对象并想要更新它,我们必须重新附加该对象。在重新附加过程中,Hibernate将检查是否存在同一对象的任何其他副本。如果它找到了,它必须告诉我们它不知道“真正的”副本是什么了。也许对我们希望保存的其他副本进行了其他更改,但Hibernate不了解它们,因为它当时没有管理它们。

Hibernate不是保存可能不好的数据,而是通过NonUniqueObjectException告诉我们这个问题。

那么我们该怎么办呢?在Hibernate 3中,我们有merge()(在Hibernate 2中,使用saveOrUpdateCopy())。此方法将强制Hibernate将来自其他分离实例的任何更改复制到要保存的实例上,从而在保存之前合并内存中的所有更改。

        Session session = sessionFactory1.openSession();
        Transaction tx = session.beginTransaction();
        Item item = (Item) session.get(Item.class, new Long(1234));
        tx.commit();
        session.close(); // end of first session, item is detached

        item.getId(); // The database identity is "1234"
        item.setDescription("my new description");
        Session session2 = sessionFactory.openSession();
        Transaction tx2 = session2.beginTransaction();
        Item item2 = (Item) session2.get(Item.class, new Long(1234));
        Item item3 = session2.merge(item); // Success!
        tx2.commit();
        session2.close();

重要的是要注意merge返回对实例的新更新版本的引用。它不会将项目重新附加到会话。如果你测试实例相等(item == item3),你会发现在这种情况下它返回false。从这一点开始,您可能希望使用item3。

值得注意的是,Java Persistence API(JPA)没有分离和重新附加对象的概念,并使用EntityManager.persist()和EntityManager.merge()。

我发现在使用Hibernate时,saveOrUpdate()通常足以满足我的需求。当我拥有可以引用相同类型对象的对象时,我通常只需要使用merge。最近,异常的原因在于代码验证引用不是递归的。作为验证的一部分,我正在将同一个对象加载到我的会话中,从而导致错误。

你在哪里遇到过这个问题?合并是否适用于您,或者您是否需要其他解决方案?您是否希望始终使用合并,或者仅在特定情况下根据需要使用合并

作者: HakunaMatata 发布者: 11.06.2013 09:21

113

31272 作者的声誉

╔══════════════╦═══════════════════════════════╦════════════════════════════════╗
║    METHOD    ║            TRANSIENT          ║            DETACHED            ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║              ║       sets id if doesn't      ║   sets new id even if object   ║
║    save()    ║     exist, persists to db,    ║    already has it, persists    ║
║              ║    returns attached object    ║ to DB, returns attached object ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║              ║       sets id on object       ║             throws             ║
║   persist()  ║     persists object to DB     ║       PersistenceException     ║
║              ║                               ║                                ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║              ║                               ║                                ║
║   update()   ║           Exception           ║     persists and reattaches    ║
║              ║                               ║                                ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║              ║  copy the state of object in  ║    copy the state of obj in    ║
║    merge()   ║     DB, doesn't attach it,    ║      DB, doesn't attach it,    ║
║              ║    returns attached object    ║     returns attached object    ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║              ║                               ║                                ║
║saveOrUpdate()║           as save()           ║            as update()         ║
║              ║                               ║                                ║
╚══════════════╩═══════════════════════════════╩════════════════════════════════╝
作者: Sergii Shevchyk 发布者: 03.09.2013 08:30

5

436 作者的声誉

我找到了一个很好的例子,显示了所有hibernate保存方法之间的差异:

http://www.journaldev.com/3481/hibernate-session-merge-vs-update-save-saveorupdate-persist-example

总之,根据以上链接:

保存()

  • 我们可以在事务外调用此方法。如果我们在没有事务的情况下使用它,并且我们在实体之间进行级联,那么除非我们刷新会话,否则只保存主实体。
  • 因此,如果从主对象映射了其他对象,则会在提交事务或刷新会话时保存它们。

坚持()

  • 它类似于在事务中使用save(),因此它是安全的并且可以处理任何级联对象。

saveOrUpdate()方法

  • 可以在有或没有事务的情况下使用,就像save()一样,如果它在没有事务的情况下使用,映射的实体将不会被保存为un; ess我们刷新会话。

  • 根据提供的数据生成插入或更新查询的结果。如果数据存在于数据库中,则执行更新查询。

更新()

  • 当我们知道我们只更新实体信息时,应该使用Hibernate更新。此操作将实体对象添加到持久上下文,并在提交事务时跟踪和保存进一步的更改。
  • 因此,即使在调用update之后,如果我们在实体中设置任何值,它们将在事务提交时更新。

合并()

  • Hibernate merge可用于更新现有值,但此方法从传递的实体对象创建副本并返回它。返回的对象是持久化上下文的一部分,并跟踪任何更改,不跟踪传递的对象。这是与所有其他方法的merge()的主要区别。

另外,对于所有这些的实际例子,请参考我上面提到的链接,它显示了所有这些不同方法的示例。

作者: OutOfMind 发布者: 12.04.2017 06:11

0

219 作者的声誉

以上答案都没有完整。虽然Leo Theobald的回答看起来最接近答案。

基本点是hibernate如何处理实体的状态以及它在状态发生变化时如何处理它们。所有事情都必须在冲洗和提交方面看到,每个人似乎都完全忽略了。

永远不要使用HIBERNATE的保存方法。忘记它甚至存在于HIBERNATE!

坚持

正如大家所解释的那样,Persist基本上将一个实体从“瞬态”状态转换为“管理”状态。此时,slush或commit可以创建insert语句。但该实体仍将处于“管理”状态。同花顺不会改变。

此时,如果你再次“坚持”,就不会有任何改变。如果我们试图坚持一个持久的实体,那么就不会有更多的存储。

当我们试图驱逐实体时,乐趣就开始了。

evict是Hibernate的一个特殊功能,它将实体从“Managed”转换为“Detached”。我们不能在一个独立的实体上调用持久性。如果我们这样做,那么Hibernate会引发异常,整个事务会在提交时回滚。

合并与更新

这两个有趣的函数在以不同方式处理时执行不同的操作。他们都试图将实体从“独立”状态转换为“托管”状态。但做得与众不同。

理解Detached意味着某种“离线”状态的事实。和管理意味着“在线”状态。

请注意以下代码:

Session ses1 = sessionFactory.openSession();

    Transaction tx1 = ses1.beginTransaction();

    HibEntity entity = getHibEntity();

    ses1.persist(entity);
    ses1.evict(entity);

    ses1.merge(entity);

    ses1.delete(entity);

    tx1.commit();

当你这样做?你认为会发生什么?如果你说这会引发异常,那么你是对的。这将引发异常,因为,merge已经在实体对象上工作,这是分离状态。但它并没有改变对象的状态。

在场景后面,merge将引发一个select查询,并基本上返回一个处于附加状态的实体副本。请注意以下代码:

Session ses1 = sessionFactory.openSession();

    Transaction tx1 = ses1.beginTransaction();
    HibEntity entity = getHibEntity();

    ses1.persist(entity);
    ses1.evict(entity);

    HibEntity copied = (HibEntity)ses1.merge(entity);
    ses1.delete(copied);

    tx1.commit();

上面的示例有效,因为merge已将新实体带入处于持久状态的上下文中。

当应用Update时,同样的工作正常,因为更新实际上不会带来像merge这样的实体副本。

Session ses1 = sessionFactory.openSession();

    Transaction tx1 = ses1.beginTransaction();

    HibEntity entity = getHibEntity();

    ses1.persist(entity);
    ses1.evict(entity);

    ses1.update(entity);

    ses1.delete(entity);

    tx1.commit();

同时在调试跟踪中我们可以看到Update没有引发像select这样的select的SQL查询。

删除

在上面的例子中我使用了delete而没有谈论删除。删除基本上将实体从托管状态转换为“已删除”状态。当刷新或提交时,将发出删除命令进行存储。

但是,可以使用persist方法将实体从“已删除”状态恢复到“托管”状态。

希望以上解释澄清任何疑问。

作者: Bharat Raj 发布者: 22.11.2018 10:23

0

58413 作者的声誉

正如我在本文中所解释的那样,您应该在大多数时候使用JPA方法,而update对于批处理任务则更喜欢。

JPA或Hibernate实体可以处于以下四种状态之一:

  • 瞬态(新)
  • 管理(持久)
  • 超脱
  • 已删除(已删除)

从一个状态到另一个状态的转换是通过EntityManager或Session方法完成的。

例如,JPA EntityManager提供以下实体状态转换方法。

在此输入图像描述

Hibernate的Session实现了所有的JPA EntityManager方法,并提供一些额外的实体状态转换方法,如savesaveOrUpdateupdate

在此输入图像描述

坚持

要将实体的状态从Transient(New)更改为Managed(Persisted),我们可以使用persistJPA提供的方法,该方法EntityManager也由Hibernate继承Session

persist方法触发PersistEventDefaultPersistEventListenerHibernate事件侦听器处理的。

因此,在执行以下测试用例时:

doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    entityManager.persist(book);

    LOGGER.info(
        "Persisting the Book entity with the id: {}", 
        book.getId()
    );
});

Hibernate生成以下SQL语句:

CALL NEXT VALUE FOR hibernate_sequence

-- Persisting the Book entity with the id: 1

INSERT INTO book (
    author, 
    isbn, 
    title, 
    id
) 
VALUES (
    'Vlad Mihalcea', 
    '978-9730228236', 
    'High-Performance Java Persistence', 
    1
)

请注意,在idBook实体附加到当前持久性上下文之前已分配。这是必需的,因为管理实体存储在一个Map结构中,其中密钥由实体类型及其标识符形成,值是实体引用。这就是为什么JPA EntityManager和Hibernate Session被称为第一级缓存的原因。

调用时persist,实体仅附加到当前运行的持久性上下文,并且可以推迟INSERT直到flush调用它。

唯一的例外是IDENTITY生成器,它立即触发INSERT,因为这是获取实体标识符的唯一方法。因此,Hibernate无法使用IDENTITY生成器批量插入实体。有关此主题的更多详细信息,请查看此文章

有关更多详细信息,请查看此文章

作者: Vlad Mihalcea 发布者: 27.02.2019 01:52
32x32