【问题标题】:Differences among save, update, saveOrUpdate, merge methods in Session?Session中save、update、saveOrUpdate、merge方法的区别?
【发布时间】:2011-11-20 11:32:39
【问题描述】:

我是 Hibernate 的新手,上周学习了 Hibernate 教程。我对 Session 类中的方法 save、update、saveOrUpdate 和 merge 有一些疑问。它们是:

  • 保存方法:用于将新创建的对象插入数据存储区。 (基本上,标识符值将是 0)。就像我创建一个新客户并调用保存操作一样,它会将其保存在数据存储中并生成标识符。

    这是正确的吗?如果我们在已经持久化的对象上调用保存,不确定会发生什么?

  • 更新方法:它用于更新数据存储中已经存在的对象。(基本上标识符值将是一些非零值)。就像我加载一个新客户并在更新某些字段值后调用更新操作一样,它会在数据存储中更新它。

    根据我的理解,它应该会失败并出现一些异常,因为根据 API 更新是针对分离对象的。它是否正确?如果是,我们应该调用什么来更新同一会话中的对象(我的意思是如果对象未分离)。还有一点是:如果我们在新创建的对象上调用 update 会发生什么?

  • saveOrUpdate 方法: 它将根据未保存值检查调用上述任一方法(它必须基于标识符零或非零值进行,对吗?)所以如果我们有持久的客户对象我们更新他的姓氏并创建一个新帐户,然后 saveOrUpdate 会处理它。

    我理解正确吗?

  • Merge 方法: 它的作用类似于更新,但在这里,如果会话中已经存在具有相同标识符的持久对象,它将更新持久对象中的分离对象值并保存它。

    但是如果当前没有与会话关联的持久化实例,这将从数据存储中加载持久化对象,然后更新加载的持久化对象中分离对象的值,然后更新它。

    我也明白了吗?

【问题讨论】:

    标签: hibernate


    【解决方案1】:

    大部分事情你都做对了,但更新的工作方式与你描述的方式略有不同。如果对象在会话中(即持久对象),则完全不需要更新。当会话被刷新时,Hibernate 处理持久化会话中对象的任何更改。对它们调用 update 将无济于事(并且可能会导致性能损失;我不确定)。

    Update 被设计为在分离的对象上调用,即那些现在在它们被加载的会话之外的对象。@hvgotcodes 的解释似乎是不正确的,因为只有当对象不是时才应该调用更新em> 在会话中。如果对象的实例已经在会话中,更新可能会失败。在这种情况下应该使用合并。它将分离对象的更改与会话中的对象(如果存在)合并。如果会话中没有对象,它将创建一个新对象。

    通常您可以完全避免调用 update/merge,但如果您最终不得不调用一个,merge 可以处理更广泛的情况。我的理解是使用 update 的唯一原因是为了更好的性能,假设你知道它不会出错。

    This thread 对其他一些休眠方法也有很好的总结。

    编辑:我只是想我应该说合并和更新之间的区别比我最初说的要多。更新将给定实体修改为持久,而合并返回一个新的持久实体。对于合并,您应该丢弃旧对象。另一个区别是,merge 通过在决定是否写入数据之前从 DB 中进行选择来进行脏检查,而 update 总是将其数据保存到 DB 中,无论它是否脏。

    可能还有其他一些小的差异。通过记录生成的 SQL 来测试 Hibernate 行为总是好的,因为行为并不总是与文档匹配,至少在我的经验中是这样。

    【讨论】:

    • “而更新总是将其数据保存到数据库中,无论它是否脏” - 这是不正确的。如果您实施 CustomEntityDirtinessStrategy,您可以使用 session.update 从两个世界中获得最佳效果:不要触发额外的选择,也不要触发未更改实体的更新。
    【解决方案2】:

    您的所有评估都完全正确。你懂的。

    对于您的第一个问题,如果我没记错的话,save 专门做了一个插入。所以再次调用 save 将导致数据库中的另一行。

    对于第二个问题,update 更新会话中的一个对象。因此,如果对象在会话中,它将更新。如果对象不在会话中,则应调用合并。我相信为分离的实例调用update 会导致异常。

    【讨论】:

    • 感谢 hvgotcodes。如果您能就灰色/引用的部分给出简短的回答,那将非常有帮助。
    • 嗨 hvgotcodes ,我不认为第一个和第二个解释是正确的。因为保存检查必须检查标识符值是否为零,但对于已经持久化的对象,它不是零。所以它不会插入新行。关于根据 api 文档更新的第二个答案也适用于 detached object 。不确定我们是否应该更新已经持久化的对象应该调用哪个方法?
    • @mohit,你真的尝试过这些东西吗?正确的单元测试并尝试一下。
    • 你的第一个答案是错误的。通过调用 save(object) 而不是一次 hibernate 不会对数据库触发一个以上的查询,因为 hibernate 将使用其第一级缓存(会话),并且 hibernate 在代理上工作。
    • 其实第一个和第二个答案都是错误的。在会话中调用两次保存只会导致一次插入,对持久对象调用更新是不必要的,但不会导致异常,您当然可以对分离对象调用更新。
    【解决方案3】:

    @Naliba 对 Update() 方法给出了很好的答案。

    下图中的休眠生命周期有助于了解上述方法。

    示例:让我们看看merge()方法的情况。

    SessionFactory factory = cfg.buildSessionFactory();
    Session session1 = factory.openSession();
    
    Student student1 = null;
    Object object1 = session1.get(Student.class, new Integer(101));
    student1 = (Student)object1;
    session1.close();
    
    student1.setMarks(97);// -->object will be in some RAM location, not in the session1 cache
    
    Session session2 = factory.openSession();
    Student student2 = null;
    Object object2 = session2.get(Student.class, new Integer(101));
    student2 = (Student)object2;
    Transaction tx=session2.beginTransaction();
    
    session2.merge(student1);
    

    以上student1处于分离状态,修改了分离对象student1,现在如果我们调用update()方法那么hibernate会抛出错误。

    在这个session2 中,我们现在将session2.merge(s1); 称为student2 对象student1 更改将被合并并保存到数据库中。

    【讨论】:

      【解决方案4】:

      session.update() - 它用于从休眠会话加载对象 Person1 的场景。现在它正在应用程序中使用 - 也可能在客户端,已更新。我们想再次保存它。我们知道数据库中的 Person 对象没有进行任何更改。所以我们可以简单地使用更新。

      session.merge() - 在上述场景中,如果在保存更改的 Person1 对象之前对人员数据进行了更改,那么我们应该使用合并。它将合并更改。

      session.save() - 它可以用来保存一个新对象。它返回可序列化的身份。

      session.persist() - 与 save() 相同,但为 void 方法,不返回任何内容。

      session.saveOrUpdate() - 此方法适用于新旧对象。如果对象是新的,它将像简单的保存一样工作,或者如果对象已经是持久的,它将像更新一样工作。

      session.lock() - 它仅用于锁定对象,或者您可以说检查对象的版本。它不是用来更新对象的。仅当您确定数据库中的对象状态未更改时,才应使用它重新附加对象。否则,它可能会覆盖更改。

      【讨论】:

        【解决方案5】:

        update() 用于分离对象和瞬态对象。如果在持久对象上调用,它将抛出一个NonUniqueObjectException,这将由merge() 解决。

        【讨论】:

        • 我不认为 update 适用于 transient 对象。如果您在 transient 对象上调用更新,将引发 StaleStateException。
        【解决方案6】:

        合并是否跟随

        Merge 有智能。在进行实际合并之前它有很多预检查(如果需要)

        1. 如果对象是瞬态的,它只是触发 INSERT 查询使对象持久化(附加到会话)
        2. 如果对象已分离,则触发选择查询以检查数据是否已修改 如果修改,则触发 UPDATE 查询,否则忽略合并任务。

        在哪里作为 session.update

        1. 如果对象是瞬态的,则抛出异常。
        2. 如果 Object 已分离,它只会触发 UPDATE 查询,而不考虑对象的数据更改。

        session.merge 比更新昂贵

        【讨论】:

          【解决方案7】:

          您应该在代码中应用 save() 和 saveOrUpdate 方法之间的差异以获得最佳性能:

          save() 方法返回数据库生成的标识符。另一方面, saveOrUpdate() 可以根据对象是否存在于数据库中来执行 INSERT 或 UPDATE。并且 saveOrUpdate 首先进行选择以确定它是否需要进行插入或更新。所以你应该使用 saveOrUpdate 以防更新查询。

          save() 和 saveOrUpdate() 方法之间的另一个关键区别是 save() 方法用于使瞬态对象变为持久状态,但 saveOurUpdate() 可以使瞬态(新对象)和分离(现有对象)对象进入持久状态。所以 saveOrUpdate() 通常用于将分离的对象重新附加到 Session 中。

          来自Difference between save and saveOrUpdate in Hibernate的帖子

          【讨论】:

            猜你喜欢
            • 2011-05-26
            • 2013-07-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-12-11
            • 2014-04-12
            • 1970-01-01
            相关资源
            最近更新 更多