【问题标题】:Whats the difference between persist() and save() in Hibernate?Hibernate 中的 persist() 和 save() 有什么区别?
【发布时间】:2011-12-27 05:09:31
【问题描述】:

通过文档,我只能找到一个区别,即 save 方法生成将对象作为生成的标识符返回,但 persist 不会。它是提供 persist 方法的唯一目的吗?如果是的话,它对程序员有什么帮助,因为即使他不打算使用生成的标识符他可以使用保存并忽略返回值。

也通过What's the advantage of persist() vs save() in Hibernate? 的这个线程来了。我可以从这个线程得到的有意义的语句是 persist() 还保证它不会执行 INSERT 语句,如果它在保存方法所做的事务边界之外被调用,但不确定我应该如何尝试在我的程序中,以便我可以获得实际的差异?

【问题讨论】:

标签: hibernate


【解决方案1】:

我做了一些模拟测试来记录 Save() 和 Persist() 之间的区别。

听起来这两种方法在处理瞬态实体时表现相同,但在处理分离实体时表现不同。

对于下面的示例,将 EmployeeVehicle 作为一个实体,将 PK 作为生成值的 vehicleId,将 vehicleName 作为其属性之一。

示例 1:处理瞬态对象

                 Session session = factory.openSession();
                 session.beginTransaction();
                 EmployeeVehicle entity = new EmployeeVehicle();
                    entity.setVehicleName("Honda");
                 session.save(entity);
                 // session.persist(entity);
                session.getTransaction().commit();
                session.close();

结果:select nextval ('hibernate_sequence') //这是为生成的车辆 ID:36

insert into Employee_Vehicle ( Vehicle_Name, Vehicle_Id) values ( Honda, 36)

Repeat the same with using persist(entity) and will result the same with new Id ( say 37 , honda ) ;

示例 2:处理分离的对象

// Session 1 
            // Get the previously saved Vehicle Entity 
           Session session = factory.openSession();
            session.beginTransaction();
            EmployeeVehicle entity = (EmployeeVehicle)session.get(EmployeeVehicle.class, 36);
           session.close();

           // Session 2
           // Here in Session 2 , vehicle entity obtained in previous session is a detached object and now we will try to save / persist it 
         (i) Using Save() to persist a detached object 
           Session session2 = factory.openSession();
            session2.beginTransaction();
                    entity.setVehicleName("Toyota");
            session2.save(entity);
            session2.getTransaction().commit();
            session2.close();

结果:您可能期望在上一个会话中获得的具有 id : 36 的车辆已更新为名称为 "Toyota" 。但是发生的情况是,一个新实体被保存在数据库中,为生成的新 ID 和名称为“Toyota”

         select nextval ('hibernate_sequence')
         insert into Employee_Vehicle ( Vehicle_Name, Vehicle_Id) values ( Toyota, 39)

         (ii) Using Persist()  to persist a detached object 

            // Session 1 
            Session session = factory.openSession();
    session.beginTransaction();
    EmployeeVehicle entity = EmployeeVehicle)session.get(EmployeeVehicle.class, 36);
    session.close();

// 会话 2 // 这里在 Session 2 中,在前一个 session 中获得的车辆实体是一个分离的对象,现在我们将尝试保存/持久化它 (i) 使用 persist() 来持久化一个分离的对象

            Session session2 = factory.openSession();
    session2.beginTransaction();
            entity.setVehicleName("Toyota");
    session2.persist(entity);
    session2.getTransaction().commit();
    session2.close();

结果:抛出异常:分离的实体传递给持久化

因此,使用 Persist() 而不是 Save() 总是更好,因为在处理会话和事务时必须小心使用 save。

【讨论】:

  • 如果实体是持久化的但没有分离,然后使用保存或持久化怎么办?
  • 一个实体如何同时处于两种状态(持久和分离)?
【解决方案2】:
  • 返回类型:两个函数都将记录插入数据库,但persist()方法的返回类型是void,而save()方法的返回类型是主键id值由hibernate生成。

  • Identifier:persist() 方法不保证标识符值会立即分配给持久化实例,分配可能在刷新时发生。

    李>
  • 事务边界:我们只能在事务内部调用 persist() 方法,因此它是安全的并且可以处理任何级联对象。 save() 方法可以在事务内部或外部调用。

  • 上下文:persist() 方法将实体对象添加到持久上下文并跟踪任何进一步的变化。任何进一步的更改都会在提交事务时保存,例如持久化。

finally persist() 方法优于 save()。

examples

【讨论】:

    【解决方案3】:

    Persist():

    • 这是一个 void 方法,不保证标识符值是 在 INSERT 之后分配给持久性实例。任务可能 发生在冲洗时间。
    • 如果从外部事务调用它不会被执行 边界。
    • 这对于具有扩展会话/持久性上下文的长期对话很有用。

    保存():

    • 执行INSERT后会返回标识符。
    • 它甚至会在事务边界之外执行。
    • 这对于长时间运行的对话没有用处。

    【讨论】:

    • 什么是休眠的“长时间对话”?
    【解决方案4】:

    save() 返回一个标识符,如果必须执行 INSERT 以获取该标识符,则无论您是在事务内部还是事务外部,此 INSERT 都会立即发生。这在具有扩展会话/持久性上下文的长期对话中不好。

    persist() 用于瞬态对象。它使瞬态实例持久化。但是,它不保证标识符值将立即分配给持久实例,分配可能发生在刷新时间。它还保证如果在事务边界之外调用它不会执行 INSERT 语句。这在具有扩展会话/持久性上下文的长期对话中很有用。

    【讨论】:

    • 这并不完全正确。 AFAIK,save 如果记录存在,则不会更新,您必须为此致电safeOrUpdatesave 在这种情况下会抛出异常。
    • 您的回答在某些部分非常混乱和错误。当您提到将 persist() 用于瞬态对象时,您的答案听起来像是 not 用于瞬态对象。另外,save() 是一个 update() 是错误的。
    【解决方案5】:
    public class TestSave {
    
    public static void main(String[] args) {
    
        Session session= HibernateUtil.getSessionFactory().openSession();
        Person person= (Person) session.get(Person.class, 1);
        System.out.println(person.getName());
        session.close();
    
        Session session1= HibernateUtil.getSessionFactory().openSession();
        session1.beginTransaction();
    
        person.setName("person saved with Persist");
        session1.getTransaction().commit();
        System.out.println(session1.save(person));
    
        //session1.persist(person);
        session1.flush();
    
        session1.close();
    
    }
    }
    

    Save 和 persist 的区别,Save 在事务之外执行。执行上述代码并检查控制台 System.out.println(session1.save(person)) 将返回标识符并再次执行它,它将增加您的标识符。现在,如果您尝试使用以下代码在数据库的 Person 表中保存另一条记录并刷新数据库表并检查数据库中的 id 列。它的值会增加。

    public class TestMain {
      public static void main(String[] args) {
        Person person = new Person();
        saveEntity(person);
     }
    private static void saveEntity(Person person) {
    person.setId(1);
     person.setName("Concretepage1");
     Session session = HibernateUtil.getSessionFactory().openSession();
     session.beginTransaction();
     session.save(person);
     session.getTransaction().commit();
     session.close();
    }
    

    如果我们尝试将数据持久化到事务边界之外,则会出现异常。

    【讨论】:

      【解决方案6】:

      save() 方法通常在外部事务中插入语句

      public class HibernateSaveExample {
      
          public static void main(String[] args) {
      
              SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
              Session session = sessionFactory.openSession();
              Student student = new Student("javabycode.com", new Date(), "USA", "1234569");
              Long studentId = (Long) session.save(student);
              System.out.println(" Identifier : " + studentId);
              System.out.println(" Successfully saved");
      
              Session session2 = sessionFactory.openSession();
              Transaction trans = session2.beginTransaction();
      
              Student student2 = new Student("javabycode.com", new Date(), "USA", "1234569");
              Long studentId2 = (Long) session2.save(student2);
              trans.commit();
              System.out.println(" Identifier : " + studentId2);
              System.out.println(" Successfully saved");
      
              sessionFactory.close();
          }
      
      }
      

      persist() 方法做不到。

      Hibernate 中 save 和 persist 方法还有一个区别:persist 是 JPA 支持的,而 save 只有 Hibernate 支持。

      来自教程Difference between save and persist method in Hibernate

      【讨论】:

        猜你喜欢
        • 2013-04-29
        • 2011-05-29
        • 2014-05-18
        • 2016-02-03
        • 2015-07-12
        • 1970-01-01
        • 1970-01-01
        • 2011-08-06
        相关资源
        最近更新 更多