Hibernate中persist()和save()方法有什么区别?

13

通过文档,我只发现了一个区别,那就是 save 方法会生成并返回对象标识符,而 persist 方法则不会。这是提供 persist 方法的唯一目的吗?如果是的话,它如何帮助程序员呢?即使他不想使用生成的标识符,他仍然可以使用 save 并忽略返回值。

我还在这个线程中发现了这个有意义的声明: persist() 还保证在事务边界外调用时不会执行插入语句,而 save 方法会执行,但我不确定应该如何在我的程序中尝试它,以便我能真正理解它们之间的差异?


可能是在Hibernate中使用persist()和save()的优势是什么?的重复问题。 - Stijn Geukens
6个回答

17

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

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

对于下面的示例,请将EmployeeVehicle作为一个实体,其主键为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();

// 第二个会话 // 在第二个会话中,上一个会话中获得的车辆实体是一个分离的对象,现在我们将尝试保存/持久化它 (i)使用persist()方法持久化一个分离的对象

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

结果: 抛出异常: 传递给persist的实体已分离

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


如果实体是持久的但未分离,然后使用save或persistent会怎样? - M Sach
一个实体怎么可能同时处于两种状态(持久化和分离)? - Kumar Manish

6
  • 返回类型:这两个函数都将记录插入数据库,但是persist()方法的返回类型是void,而save()方法的返回类型是hibernate生成的主键id值。

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

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

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

最后,persist()方法比save()更好。

示例


3

Persist():

  • 这是一个无返回值的方法,并不能保证在执行INSERT后,标识符值已分配给持久化实例。分配可能会在提交时发生。
  • 如果在事务边界外调用它,则不会被执行。
  • 对于具有扩展会话/持久性上下文的长时间运行的对话非常有用。

Save():

  • 执行INSERT后,它将返回标识符。
  • 即使在事务边界之外,它也将被执行。
  • 对于长时间运行的对话并不实用。

1
Hibernate的“长时间运行对话”究竟是什么? - Kumar Manish

3

save() 返回一个标识符,如果需要执行 INSERT 来获取该标识符,则无论是否在事务内部或外部,都会立即执行此 INSERT。这在与扩展的 Session/持久化上下文进行长时间对话时不好。

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


7
这并不完全正确。据我所知,如果记录已存在, save 不会更新它,您需要调用 safeOrUpdate 来实现此操作。在这种情况下,save 会抛出异常。 - Stefan Steinegger
你的回答非常令人困惑,并且在某些部分是错误的。当你提到persist()被用于瞬态对象时,你的回答听起来好像save() 被用于瞬态对象上。此外,将save()视为update()也是错误的。 - Kumar Manish

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

如果我们试图在事务边界外持久化数据,就会引发异常。

0

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 支持。

来自教程 Hibernate 中 save 和 persist 方法的区别


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接