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

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

我到目前为止确定的方法是:

  • 保存()
  • 更新()
  • saveOrUpdate()方法
  • saveOrUpdateCopy()
  • 合并()
  • 坚持()

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

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

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

更新尝试使用现有的标识符来坚持实体。 如果没有标识符存在,我相信会引发exception。

saveOrUpdateCopy这已弃用,不应再使用。 相反,有…

合并现在,这是我的知识开始动摇的地方。 这里最重要的是瞬态,分离和持久实体之间的区别。 有关对象状态的更多信息, 请看这里 。 保存和更新,你正在处理持久对象。 他们被链接到一个会话,所以Hibernate知道发生了什么变化。 但是当你有一个临时对象时,就不会涉及到任何会话。 在这些情况下,您需要使用合并更新并坚持保存。

坚持如上所述,这是用于临时对象。 它不返回生成的ID。

╔══════════════╦═══════════════════════════════╦════════════════════════════════╗ ║ 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() ║ ║ ║ ║ ║ ╚══════════════╩═══════════════════════════════╩════════════════════════════════╝ 
  • 请参阅Hibernate论坛,了解持久性和保存之间细微差异的解释。 看起来不同的是INSERT语句最终执行的时间。 既然保存返回标识符,INSERT语句必须立即执行,而不pipe事务的状态如何(通常这是一件坏事)。 Persist将不会执行当前正在运行的事务之外的任何语句来分配标识符。 保存/保持两个工作在瞬态实例 ,即没有标识符分配的实例,因此不保存在数据库中。

  • 更新合并都可以在分离的实例上工作,即在DB中具有对应条目但当前未连接到(或由其pipe理)的实例。 它们之间的区别是传递给函数的实例发生了什么。 更新会尝试重新连接实例,这意味着现在可能没有其他实例连接到Session,否则会引发exception。 合并 ,但是,只是将所有的值复制到Session中的一个持久化实例(如果它当前没有加载,将被加载)。 input对象不会更改。 所以合并更新更普遍,但可能会使用更多的资源。

这个链接解释得很好:

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

我们都遇到了我们偶尔遇到的那些问题,当我们再次看到他们时,我们知道我们已经解决了这个问题,但却不记得如何。

在Hibernate中使用Session.saveOrUpdate()时抛出的NonUniqueObjectException是我的一个。 我将为复杂的应用程序添加新的function。 我所有的unit testing工作正常。 然后在testing用户界面时,试图保存一个对象,我开始收到一个exception消息,“具有相同标识符值的不同对象已经与该会话相关联”。下面是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(); 

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

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

如果我们然后修改我们的分离的对象,并想更新它,我们必须重新附加对象。 在重新连接的过程中,Hibernate会检查是否还有其他同一个对象的拷贝。 如果发现任何问题,它必须告诉我们,它不知道什么是“真正的”副本。 也许还有其他更改,我们希望保存其他副本,但Hibernate不知道他们,因为它不是在pipe理他们。

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(); 

注意合并返回实例的最新更新版本的引用是很重要的。 这不是重新连接到会议的项目。 如果testing实例相等(item == item3),在这种情况下你会发现它返回false。 从这一点开始,您可能会想要使用item3。

Java Persistence API(JPA)没有分离和重新连接对象的概念,并使用EntityManager.persist()和EntityManager.merge(),这一点也很重要。

我发现一般情况下,使用Hibernate时,saveOrUpdate()通常足以满足我的需求。 当我有可以引用相同types的对象的对象时,我通常只需要使用合并。 最近,exception的原因是在代码validation参考是不recursion的。 作为validation的一部分,我将相同的对象加载到会话中,导致错误。

你在哪里遇到过这个问题? 为你合并工作,还是你需要另一个解决scheme? 你喜欢总是使用合并,或者只是根据特定情况需要使用合并

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

如果我们的生成器类被赋值,那么save()persist( )方法之间没有区别。 因为发生器的赋值意味着,作为一个程序员,我们需要给主键值保存在数据库中[希望你知道这个发生器的概念]如果分配的发生器类别以外的情况下,假设如果我们的生成器类名称是增量意味着hibernate它自己会分配主键ID值到数据库的权利[除了分配的发电机,hibernate只用于照顾主键ID值记住],所以在这种情况下,如果我们调用save()persist()方法,然后它会将logging正常插入到数据库中但是听到的是, save()方法可以返回由hibernate生成的主键id值,我们可以看到它

 long s = session.save(k); 

在这种情况下, persist()永远不会给客户端返回任何值。

我发现了一个很好的例子,显示了所有的hibernate保存方法之间的区别:

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

简而言之,根据以上链接:

保存()

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

坚持()

  • 它类似于在事务中使用save(),所以它是安全的并且负责任何级联的对象。

saveOrUpdate()方法

  • 可以与事务一起使用,也可以不使用事务,就像save()一样,如果没有事务使用它,映射的实体也不会被保存;我们会刷新会话。

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

更新()

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

合并()

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

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

请注意,如果您在分离的对象上调用更新,则无论是否更改对象,总会在数据库中执行更新。 如果它不是你想要的,你应该使用LockMode.None的Session.lock()。

只有当对象在当前会话的范围之外被更改(当处于分离模式时),才应该调用更新。

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