# Hiberate `save()`和`saveOrUpdate()`方法

> 原文： [https://howtodoinjava.com/hibernate/hibernate-save-and-saveorupdate/](https://howtodoinjava.com/hibernate/hibernate-save-and-saveorupdate/)

[**Hiberate**](//howtodoinjava.com/hibernate-tutorials/ "Hibernate Tutorials") 仅与[**持久实体**](//howtodoinjava.com/hibernate/hibernate-entity-persistence-lifecycle-states/ "Hibernate Entity / Persistence LifeCycle States")一起使用，并且持久实体是附加到任何 Hiberate 会话的类。 请注意，使用 Hiberate 注解映射的类的实例的创建不会自动将对象持久保存到数据库中。 将其附加到有效的 Hiberate 会话后，必须显式保存它。

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

## 1\. Hibernate `save()`方法

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

```java
public Serializable save(Object object) throws HibernateException
public Serializable save(String entityName,Object object) throws HibernateException

```

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

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

```java
@Entity 
@Table(name = "Employee")
public class EmployeeEntity implements Serializable
{
   private static final long serialVersionUID = -1798070786993154676L;
   @Id
   @Column(name = "ID", unique = true, nullable = false)
   private Integer	employeeId;

   @Column(name = "FIRST_NAME", unique = false, nullable = false, length = 100)
   private String	firstName;

   @Column(name = "LAST_NAME", unique = false, nullable = false, length = 100)
   private String	lastName;

   @Override
   public boolean equals(Object o) {
       if (this == o) return true;
       if (!(o instanceof EmployeeEntity)) return false;

       EmployeeEntity otherEmployee = (EmployeeEntity) o;

       if (getEmployeeId() != null ?
           !getEmployeeId().equals(otherEmployee.getEmployeeId()) : otherEmployee.getEmployeeId() != null)
           return false;
       if (getFirstName() != null ?
           !getFirstName().equals(otherEmployee.getFirstName()) : otherEmployee.getFirstName() != null)
           return false;
       if (getLastName() != null ?
           !getLastName().equals(otherEmployee.getLastName()) : otherEmployee.getLastName() != null)
           return false;

       return true;
   }

   @Override
   public int hashCode() {
   int result = getEmployeeId() != null ? getEmployeeId().hashCode() : 0;
       result = 31 * result + (getFirstName() != null ? getFirstName().hashCode() : 0);
       result = 31 * result + (getLastName() != null?getLastName().hashCode() : 0);
       return result;
   }

   //Getters and Setters are hidden here
}

```

现在，保存此 Hiberate 实体。

```java
public class SimplestSaveEntityExample
{
   public static void main(String[] args)
   {
      Session sessionOne = HibernateUtil.getSessionFactory().openSession();
      sessionOne.beginTransaction();

      //Create new Employee object
      EmployeeEntity emp = new EmployeeEntity();
      emp.setEmployeeId(1);
      emp.setFirstName("Lokesh");
      emp.setLastName("Gupta");

      //Save employee
      sessionOne.save(emp);

      sessionOne.getTransaction().commit();
      HibernateUtil.shutdown();
   }    
}

```

程序输出。

```java
Hibernate: insert into Employee (FIRST_NAME, LAST_NAME, ID) values (?, ?, ?)

```

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

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

```java
public class SaveEntityAgainInAnotherSession
{
   public static void main(String[] args)
   {
      Session sessionOne = HibernateUtil.getSessionFactory().openSession();
      sessionOne.beginTransaction();

      //Create new Employee object
      EmployeeEntity emp = new EmployeeEntity();
      emp.setEmployeeId(1);
      emp.setFirstName("Lokesh");
      emp.setLastName("Gupta");

      //Save employee
      sessionOne.save(emp);
      sessionOne.getTransaction().commit();

      Session sessionTwo = HibernateUtil.getSessionFactory().openSession();
      sessionTwo.beginTransaction();

      emp.setLastName("temp");
      //Save employee again second time
      sessionTwo.save(emp);

      sessionTwo.getTransaction().commit();
      HibernateUtil.shutdown();
   }    
}

```

程序输出：

```java
Hibernate: insert into Employee (FIRST_NAME, LAST_NAME, ID) values (?, ?, ?)
Hibernate: insert into Employee (FIRST_NAME, LAST_NAME, ID) values (?, ?, ?)
 WARN SqlExceptionHelper:144 - SQL Error: -104, SQLState: 23000
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 (?, ?, ?)]
 INFO AbstractBatchImpl:208 - HHH000010: On release of batch it still contained JDBC statements

```

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

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

看下面的例子。

```java
public class SaveEntityAgainInSameSession
{
   public static void main(String[] args)
   {
      Session sessionOne = HibernateUtil.getSessionFactory().openSession();
      sessionOne.beginTransaction();

      //Create new Employee object
      EmployeeEntity emp = new EmployeeEntity();
      emp.setEmployeeId(1);
      emp.setFirstName("Lokesh");
      emp.setLastName("Gupta");

      //Save employee
      sessionOne.save(emp);

      emp.setLastName("temp");
      //Save employee again second time
      sessionOne.save(emp);

      sessionOne.getTransaction().commit();
      HibernateUtil.shutdown();
   }    
}

```

程序输出：

```java
Hibernate: insert into Employee (FIRST_NAME, LAST_NAME, ID) values (?, ?, ?)
Hibernate: update Employee set FIRST_NAME=?, LAST_NAME=? where ID=?

```

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

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

#### 1.2 持久实体的状态变化

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

```java
public class NoSaveCallForPersistentEntity
{
   public static void main(String[] args)
   {
      Session sessionOne = HibernateUtil.getSessionFactory().openSession();
      sessionOne.beginTransaction();

      //Create new Employee object
      EmployeeEntity emp = new EmployeeEntity();
      emp.setEmployeeId(1);
      emp.setFirstName("Lokesh");
      emp.setLastName("Gupta");

      //Save employee
      sessionOne.save(emp);

      emp.setLastName("temp");

      sessionOne.getTransaction().commit();

      //Let's see what got updated in DB
      Session sessionTwo = HibernateUtil.getSessionFactory().openSession();
      sessionTwo.beginTransaction();

      EmployeeEntity employee = ( EmployeeEntity ) sessionTwo.load(EmployeeEntity.class, 1);
      System.out.println(employee.getLastName());

      sessionTwo.getTransaction().commit();
      HibernateUtil.shutdown();
   }    
}

```

程序输出：

```java
Hibernate: insert into Employee (FIRST_NAME, LAST_NAME, ID) values (?, ?, ?)
Hibernate: update Employee set FIRST_NAME=?, LAST_NAME=? where ID=?

Hibernate: select employeeen0_.ID as ID1_1_0_, employeeen0_.FIRST_NAME as FIRST_NA2_1_0_, 
employeeen0_.LAST_NAME as LAST_NAM3_1_0_ from Employee employeeen0_ where employeeen0_.ID=?

temp

```

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

## 2\. Hiberate `saveOrUpdate()`方法

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

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

#### 2.1 Hibernate `saveOrUpdate()`示例

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

```java
public class SaveOrUpdateMethodExample
{
   public static void main(String[] args)
   {
      Session sessionOne = HibernateUtil.getSessionFactory().openSession();
      sessionOne.beginTransaction();

      //Create new Employee object
      EmployeeEntity emp = new EmployeeEntity();
      emp.setEmployeeId(1);
      emp.setFirstName("Lokesh");
      emp.setLastName("Gupta");

      //Save employee
      sessionOne.save(emp);
      sessionOne.getTransaction().commit();

      Session sessionTwo = HibernateUtil.getSessionFactory().openSession();
      sessionTwo.beginTransaction();

      emp.setLastName("temp");
      //Save employee again second time
      sessionTwo.saveOrUpdate(emp);

      sessionTwo.getTransaction().commit();
      HibernateUtil.shutdown();
   }  
}

```

程序输出：

```java
Hibernate: insert into Employee (FIRST_NAME, LAST_NAME, ID) values (?, ?, ?)
Hibernate: select employeeen_.ID, employeeen_.FIRST_NAME as FIRST_NA2_1_, employeeen_.LAST_NAME as 
		LAST_NAM3_1_ from Employee employeeen_ where employeeen_.ID=?
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()`方法相关的问题是否尚不清楚或需要更多说明。

学习愉快！