原文: https://howtodoinjava.com/hibernate/hibernate-save-and-saveorupdate/

Hiberate 仅与持久实体一起使用,并且持久实体是附加到任何 Hiberate 会话的类。 请注意,使用 Hiberate 注解映射的类的实例的创建不会自动将对象持久保存到数据库中。 将其附加到有效的 Hiberate 会话后,必须显式保存它。

在本教程中,学习在不同用例下使用 hibernate save()saveOrUpdate()方法。

1. Hibernate save()方法

在 Hiberate 下,我们通常使用save()方法的以下两个版本之一:

  1. public Serializable save(Object object) throws HibernateException
  2. public Serializable save(String entityName,Object object) throws HibernateException

两种save()方法都将瞬态对象引用(不能为null)作为参数。 第二种方法采用了额外的参数entityName,如果您已将多个实体映射到 Java 类,则该参数很有用。 在这里,您可以使用save()方法指定要保存的实体。

一个演示 hibernate save()方法的简单示例。

  1. @Entity
  2. @Table(name = "Employee")
  3. public class EmployeeEntity implements Serializable
  4. {
  5. private static final long serialVersionUID = -1798070786993154676L;
  6. @Id
  7. @Column(name = "ID", unique = true, nullable = false)
  8. private Integer employeeId;
  9. @Column(name = "FIRST_NAME", unique = false, nullable = false, length = 100)
  10. private String firstName;
  11. @Column(name = "LAST_NAME", unique = false, nullable = false, length = 100)
  12. private String lastName;
  13. @Override
  14. public boolean equals(Object o) {
  15. if (this == o) return true;
  16. if (!(o instanceof EmployeeEntity)) return false;
  17. EmployeeEntity otherEmployee = (EmployeeEntity) o;
  18. if (getEmployeeId() != null ?
  19. !getEmployeeId().equals(otherEmployee.getEmployeeId()) : otherEmployee.getEmployeeId() != null)
  20. return false;
  21. if (getFirstName() != null ?
  22. !getFirstName().equals(otherEmployee.getFirstName()) : otherEmployee.getFirstName() != null)
  23. return false;
  24. if (getLastName() != null ?
  25. !getLastName().equals(otherEmployee.getLastName()) : otherEmployee.getLastName() != null)
  26. return false;
  27. return true;
  28. }
  29. @Override
  30. public int hashCode() {
  31. int result = getEmployeeId() != null ? getEmployeeId().hashCode() : 0;
  32. result = 31 * result + (getFirstName() != null ? getFirstName().hashCode() : 0);
  33. result = 31 * result + (getLastName() != null?getLastName().hashCode() : 0);
  34. return result;
  35. }
  36. //Getters and Setters are hidden here
  37. }

现在,保存此 Hiberate 实体。

  1. public class SimplestSaveEntityExample
  2. {
  3. public static void main(String[] args)
  4. {
  5. Session sessionOne = HibernateUtil.getSessionFactory().openSession();
  6. sessionOne.beginTransaction();
  7. //Create new Employee object
  8. EmployeeEntity emp = new EmployeeEntity();
  9. emp.setEmployeeId(1);
  10. emp.setFirstName("Lokesh");
  11. emp.setLastName("Gupta");
  12. //Save employee
  13. sessionOne.save(emp);
  14. sessionOne.getTransaction().commit();
  15. HibernateUtil.shutdown();
  16. }
  17. }

程序输出。

  1. Hibernate: insert into Employee (FIRST_NAME, LAST_NAME, ID) values (?, ?, ?)

1.1 在持久实体上调用save()方法

我们保存了Employee实体。 太简单。 但是实际上,它不是那么简单的用例。 在那里,您可能需要再次更新员工实体,然后在另一个会话中再次保存。 您是否应该再次调用save()方法? 我们来看看。

  1. public class SaveEntityAgainInAnotherSession
  2. {
  3. public static void main(String[] args)
  4. {
  5. Session sessionOne = HibernateUtil.getSessionFactory().openSession();
  6. sessionOne.beginTransaction();
  7. //Create new Employee object
  8. EmployeeEntity emp = new EmployeeEntity();
  9. emp.setEmployeeId(1);
  10. emp.setFirstName("Lokesh");
  11. emp.setLastName("Gupta");
  12. //Save employee
  13. sessionOne.save(emp);
  14. sessionOne.getTransaction().commit();
  15. Session sessionTwo = HibernateUtil.getSessionFactory().openSession();
  16. sessionTwo.beginTransaction();
  17. emp.setLastName("temp");
  18. //Save employee again second time
  19. sessionTwo.save(emp);
  20. sessionTwo.getTransaction().commit();
  21. HibernateUtil.shutdown();
  22. }
  23. }

程序输出:

  1. Hibernate: insert into Employee (FIRST_NAME, LAST_NAME, ID) values (?, ?, ?)
  2. Hibernate: insert into Employee (FIRST_NAME, LAST_NAME, ID) values (?, ?, ?)
  3. WARN SqlExceptionHelper:144 - SQL Error: -104, SQLState: 23000
  4. ERROR SqlExceptionHelper:146 - Violation of unique constraint SYS_PK_49: duplicate value(s) for column(s) ID in statement [insert into Employee (FIRST_NAME, LAST_NAME, ID) values (?, ?, ?)]
  5. INFO AbstractBatchImpl:208 - HHH000010: On release of batch it still contained JDBC statements

Hiberate 在这里试图再次插入实体。 尽管由于主键检查而导致失败,但其他实体的检查可能不存在,并且最终可能会出现重复的行。

注意:虽然第二种save()方法导致在不同会话中重复行,但是在同一会话中它们将正常工作。

看下面的例子。

  1. public class SaveEntityAgainInSameSession
  2. {
  3. public static void main(String[] args)
  4. {
  5. Session sessionOne = HibernateUtil.getSessionFactory().openSession();
  6. sessionOne.beginTransaction();
  7. //Create new Employee object
  8. EmployeeEntity emp = new EmployeeEntity();
  9. emp.setEmployeeId(1);
  10. emp.setFirstName("Lokesh");
  11. emp.setLastName("Gupta");
  12. //Save employee
  13. sessionOne.save(emp);
  14. emp.setLastName("temp");
  15. //Save employee again second time
  16. sessionOne.save(emp);
  17. sessionOne.getTransaction().commit();
  18. HibernateUtil.shutdown();
  19. }
  20. }

程序输出:

  1. Hibernate: insert into Employee (FIRST_NAME, LAST_NAME, ID) values (?, ?, ?)
  2. Hibernate: update Employee set FIRST_NAME=?, LAST_NAME=? where ID=?

令人困惑。 对? 让我们简单点。 规则如下:

请记住,您不应在持久实体(与任何 Hibernate 会话相关联的实体)上调用save()方法。 对持久实体所做的任何更改都会自动保存。

1.2 持久实体的状态变化

对持久实体的任何更改都会自动保存。 让我们以简单的示例了解这一概念。

  1. public class NoSaveCallForPersistentEntity
  2. {
  3. public static void main(String[] args)
  4. {
  5. Session sessionOne = HibernateUtil.getSessionFactory().openSession();
  6. sessionOne.beginTransaction();
  7. //Create new Employee object
  8. EmployeeEntity emp = new EmployeeEntity();
  9. emp.setEmployeeId(1);
  10. emp.setFirstName("Lokesh");
  11. emp.setLastName("Gupta");
  12. //Save employee
  13. sessionOne.save(emp);
  14. emp.setLastName("temp");
  15. sessionOne.getTransaction().commit();
  16. //Let's see what got updated in DB
  17. Session sessionTwo = HibernateUtil.getSessionFactory().openSession();
  18. sessionTwo.beginTransaction();
  19. EmployeeEntity employee = ( EmployeeEntity ) sessionTwo.load(EmployeeEntity.class, 1);
  20. System.out.println(employee.getLastName());
  21. sessionTwo.getTransaction().commit();
  22. HibernateUtil.shutdown();
  23. }
  24. }

程序输出:

  1. Hibernate: insert into Employee (FIRST_NAME, LAST_NAME, ID) values (?, ?, ?)
  2. Hibernate: update Employee set FIRST_NAME=?, LAST_NAME=? where ID=?
  3. Hibernate: select employeeen0_.ID as ID1_1_0_, employeeen0_.FIRST_NAME as FIRST_NA2_1_0_,
  4. employeeen0_.LAST_NAME as LAST_NAM3_1_0_ from Employee employeeen0_ where employeeen0_.ID=?
  5. temp

在上面的示例中,我们使用第一种save()方法使emp对象持久化。 之后,当我们将姓氏更新为“temp”时,将按预期执行更新查询。 我们也在返回的数据中对此进行了验证。 这是使用 Hiberate 持久化实体的正确方法。

2. Hiberate saveOrUpdate()方法

在讨论save()方法时,我们忘记了必须在另一个会话中保存持久化实体而导致重复键错误的情况。 这也是一个有效的方案。

要处理这种情况,必须使用saveOrUpdate()方法。 严格来说,即使对于非持久化实体,也应使用saveOrUpdate()。 就个人而言,我认为这样做没有任何危害。 虽然,这可能会让您有些粗心。 所以要小心。

2.1 Hibernate saveOrUpdate()示例

让我们看看如何将saveOrUpdate()方法与save()方法持久化的实体一起使用。

  1. public class SaveOrUpdateMethodExample
  2. {
  3. public static void main(String[] args)
  4. {
  5. Session sessionOne = HibernateUtil.getSessionFactory().openSession();
  6. sessionOne.beginTransaction();
  7. //Create new Employee object
  8. EmployeeEntity emp = new EmployeeEntity();
  9. emp.setEmployeeId(1);
  10. emp.setFirstName("Lokesh");
  11. emp.setLastName("Gupta");
  12. //Save employee
  13. sessionOne.save(emp);
  14. sessionOne.getTransaction().commit();
  15. Session sessionTwo = HibernateUtil.getSessionFactory().openSession();
  16. sessionTwo.beginTransaction();
  17. emp.setLastName("temp");
  18. //Save employee again second time
  19. sessionTwo.saveOrUpdate(emp);
  20. sessionTwo.getTransaction().commit();
  21. HibernateUtil.shutdown();
  22. }
  23. }

程序输出:

  1. Hibernate: insert into Employee (FIRST_NAME, LAST_NAME, ID) values (?, ?, ?)
  2. Hibernate: select employeeen_.ID, employeeen_.FIRST_NAME as FIRST_NA2_1_, employeeen_.LAST_NAME as
  3. LAST_NAM3_1_ from Employee employeeen_ where employeeen_.ID=?
  4. Hibernate: update Employee set FIRST_NAME=?, LAST_NAME=? where ID=?

现在,我们可以使用saveOrUpdate()方法保存实体并更新实体。

请记住,如果您使用了saveOrUpdate()方法代替了上面的save()方法,那么结果也将是相同的。 saveOrUpdate()既可以用于持久实体也可以用于非持久实体。 持久化实体将得到更新,并且瞬态实体将被插入数据库中。

3. 关于生产代码的建议 - 最佳实践

尝试在生产代码中使用上述代码是不明智的。 理想情况下,您要做的是将 VO 对象传递到 DAO 层,从会话中加载实体,并通过将 VO 数据复制到该实体来更新实体。 这意味着更新是在持久对象上进行的,实际上我们根本不必调用Session.save()Session.saveOrUpdate()

一旦对象处于持久状态,当您更改对象的字段和属性时,Hibernate 将管理数据库本身的更新。 真是太好了。

4. 总结

  1. Save()方法将对象存储到数据库中。 它将坚持给定的瞬时实例,首先分配一个生成的标识符。 它返回创建的实体的 ID。
  2. SaveOrUpdate()根据标识符是否存在来调用save()update()。 例如,如果标识符不存在,则将调用save()或将调用update()
  3. 由于 Hiberate 管理持久对象中所做的所有更改,因此实际上调用save()saveOrUpdate()方法的机会很少。

让我知道 hibernate save()saveOrUpdate()方法相关的问题是否尚不清楚或需要更多说明。

学习愉快!