在Hibernate中persist()vs save()的优点是什么?

Ant*_*nio 159 java hibernate

谁能告诉我在Hibernate 中persist()vs 的优势是save()什么?

Bal*_*a R 150

来自这篇论坛帖子

persist()很明确.它使瞬态实例持久化.但是,它不保证标识符值将立即分配给持久性实例,分配可能在刷新时发生.该规范没有说明,这是我遇到的问题persist().

persist()还保证如果在事务边界之外调用它,它将不会执行INSERT语句.这在具有扩展会话/持久性上下文的长时间运行的对话中非常有用.

需要一种类似的方法persist().

save()不保证相同,它返回一个标识符,如果必须执行INSERT来获取标识符(例如"身份"生成器,而不是"序列"),无论你是在内部还是外部,都会立即发生INSERT.交易.这与使用扩展的会话/持久性上下文的长时间对话不太好.

  • 从同一篇文章中添加更多内容,发牢骚:"可悲的是,5年之后,这个主题仍然是关于这个主题的唯一明确的信息来源.虽然详细,但Hibernate文档除了最简单的用法信息之外都没有.为什么Christian的最后一篇文章不在Session javadoc中,这只是另一个Hibernate文档的谜团." (43认同)
  • 我最近在一对多双向映射中使用了save和persist.我发现保存没有级联到孩子,即只有父保存/插入表中.但是,persist完成了在一次调用中保存Parent和Child的任务.我使用的是复合ID而不是生成的ID. (2认同)

Zeu*_*eus 61

我对save()vs persist()进行了很好的研究,包括多次在我的本地机器上运行它.以前的所有解释都令人困惑,并且不正确.经过深入研究后,我将下面的save()和persist()进行了比较.

Save()

  1. 保存后返回生成的Id.它的Serializable返回类型.
  2. 立即将值保存到DB并跟踪实体直到会话结束(我试图在事务之外更改实体值,它在会话提交时不显示任何效果)
  3. 将更改保存到事务外部的数据库中.
  4. 将生成的id分配给您持久保存的实体
  5. 分离对象的Session.save()将在表中创建一个新行.

Persist()

  1. 保存后不返回生成的Id.它的返回类型.
  2. 立即将值保存到DB并跟踪实体直到会话结束.(我试图更改事务之外的实体值,它在会话提交时不显示任何效果)
  3. 不将更改保存到事务外部的数据库中.
  4. generated id您分配给您持久存在的实体
  5. session.persist()对于一个分离的对象将抛出,PersistentObjectException因为它是不允许的.

所有这些都经过了尝试/测试Hibernate v4.0.1.

  • 当我使用persist方法提交事务后测试时,值不保存到DB (2认同)

小智 24

我做了一些模拟测试记录之间的差别save()persist().

听起来这两种方法在处理Transient Entity时表现相同,但在处理Detached Entity时有所不同.

对于下面的示例,将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();
Run Code Online (Sandbox Code Playgroud)

结果:

select nextval ('hibernate_sequence') // This is for vehicle Id generated : 36
insert into Employee_Vehicle ( Vehicle_Name, Vehicle_Id) values ( Honda, 36)
Run Code Online (Sandbox Code Playgroud)

请注意,当您获得已保留的对象并保存它时,结果是相同的

EmployeeVehicle entity =  (EmployeeVehicle)session.get(EmployeeVehicle.class, 36);
entity.setVehicleName("Toyota");
session.save(entity);    -------> **instead of session.update(entity);**
// session.persist(entity);
Run Code Online (Sandbox Code Playgroud)

重复相同的使用persist(entity),并将与新的Id(例如37,本田)相同;

示例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();
Run Code Online (Sandbox Code Playgroud)

结果:您可能希望在上一个会话中获得的ID为36的车辆更新为名称为"Toyota".但是会发生的事情是新的实体保存在数据库中,生成新的Id并且名称为"Toyota"

select nextval ('hibernate_sequence')
insert into Employee_Vehicle ( Vehicle_Name, Vehicle_Id) values ( Toyota, 39)
Run Code Online (Sandbox Code Playgroud)

使用persist来持久化分离的实体

// (ii) Using Persist()  to persist a detached
// Session 1 
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
Session session2 = factory.openSession();
session2.beginTransaction();
entity.setVehicleName("Toyota");
session2.persist(entity);
session2.getTransaction().commit();
session2.close();
Run Code Online (Sandbox Code Playgroud)

结果:

Exception being thrown : detached entity passed to persist
Run Code Online (Sandbox Code Playgroud)

因此,使用Persist()而不是Save()总是更好,因为在处理Transient对象时必须小心使用save.

重要说明:在上面的示例中,车辆实体的pk是生成的值,因此当使用save()来保持分离的实体时,hibernate会生成一个新的id来持久化.但是,如果此pk不是生成的值,则会导致异常声明密钥被违反.


CFL*_*eff 13

关于Hibernate中不同的持久化方法,这个问题有一些很好的答案.要直接回答您的问题,使用save(),无论事务状态如何,都会立即执行insert语句.它返回插入的键,以便您可以执行以下操作:

long newKey = session.save(myObj);
Run Code Online (Sandbox Code Playgroud)

因此,如果需要立即为持久性实例分配标识符,请使用save().

使用persist(),insert语句在事务中执行,不一定立即执行.在大多数情况下这是优选的.

如果您不需要插入与事务不按顺序发生并且不需要返回插入的键,请使用persist().


Gau*_*mar 6

基本规则说:

对于具有生成标识符的实体:

save() :除了使对象持久化之外,它还立即返回实体的标识符。因此立即触发插入查询。

persist() :它返回持久对象。它没有任何立即返回标识符的强制,因此它不保证会立即触发插入。它可能会立即触发插入,但不能保证。在某些情况下,查询可能会立即触发,而在其他情况下,它可能会在会话刷新时间触发。

对于具有指定标识符的实体:

save():它立即返回一个实体的标识符。由于标识符在调用 save 之前已分配给实体,因此不会立即触发 insert。它在会话刷新时间被触发。

persist() :与保存相同。它还在冲洗时触发插入。

假设我们有一个实体,它使用如下生成的标识符:

@Entity
@Table(name="USER_DETAILS")
public class UserDetails {
    @Id
    @Column(name = "USER_ID")
    @GeneratedValue(strategy=GenerationType.AUTO)
    private int userId;

    @Column(name = "USER_NAME")
    private String userName;

    public int getUserId() {
        return userId;
    }
    public void setUserId(int userId) {
        this.userId = userId;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
}
Run Code Online (Sandbox Code Playgroud)

节省() :

    Session session = sessionFactory.openSession();
    session.beginTransaction();
    UserDetails user = new UserDetails();
    user.setUserName("Gaurav");
    session.save(user); // Query is fired immediately as this statement is executed.
    session.getTransaction().commit();
    session.close();
Run Code Online (Sandbox Code Playgroud)

坚持():

    Session session = sessionFactory.openSession();
    session.beginTransaction();
    UserDetails user = new UserDetails();
    user.setUserName("Gaurav");
    session.persist(user); // Query is not guaranteed to be fired immediately. It may get fired here.
    session.getTransaction().commit(); // If it not executed in last statement then It is fired here.
    session.close();
Run Code Online (Sandbox Code Playgroud)

现在假设我们定义了相同的实体,没有 id 字段生成注释,即 ID 将被手动分配。

@Entity
@Table(name="USER_DETAILS")
public class UserDetails {
    @Id
    @Column(name = "USER_ID")
    private int userId;

    @Column(name = "USER_NAME")
    private String userName;

    public int getUserId() {
        return userId;
    }
    public void setUserId(int userId) {
        this.userId = userId;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
}
Run Code Online (Sandbox Code Playgroud)

对于保存():

Session session = sessionFactory.openSession();
session.beginTransaction();
UserDetails user = new UserDetails();
user.setUserId(1);
user.setUserName("Gaurav");
session.save(user); // Query is not fired here since id for object being referred by user is already available. No query need to be fired to find it. Data for user now available in first level cache but not in db.
session.getTransaction().commit();// Query will be fired at this point and data for user will now also be available in DB
session.close();
Run Code Online (Sandbox Code Playgroud)

对于 persist() :

Session session = sessionFactory.openSession();
session.beginTransaction();
UserDetails user = new UserDetails();
user.setUserId(1);
user.setUserName("Gaurav");
session.persist(user); // Query is not fired here.Object is made persistent. Data for user now available in first level cache but not in db.
session.getTransaction().commit();// Query will be fired at this point and data for user will now also be available in DB
session.close();
Run Code Online (Sandbox Code Playgroud)

当从事务中调用 save 或 persist 时,上述情况是正确的。

save 和 persist 之间的其他不同点是:

  1. save() 可以在事务之外调用。如果使用分配的标识符,则因为 id 已经可用,所以不会立即触发插入查询。只有在刷新会话时才会触发查询。

  2. 如果使用了生成的标识符,则由于需要生成 id,因此会立即触发插入。但它只保存主要实体。如果实体有一些级联实体,那么这些实体此时不会保存在 db 中。当会话刷新时,它们将被保存。

  3. 如果persist() 在事务之外,则无论使用何种标识符(生成或分配),仅在刷新会话时才会触发插入。

  4. 如果通过持久对象调用 save ,则使用更新查询保存实体。


Dav*_*ham 6

以下是帮助您获得持久化和保存方法的差异:

  • save和persist之间的第一个区别是返回类型.persist方法的返回类型为void,而save
    方法的返回类型为Serializable对象.
  • persist()方法不保证标识符值将立即分配给持久状态,分配可能在刷新时发生.

  • 如果在事务边界之外调用,则persist()方法不会执行插入查询.同时,save()方法返回一个标识符,以便立即执行插入查询以获取标识符,无论它是在事务内部还是外部.

  • persist方法在事务边界之外调用,在具有扩展Session上下文的长时间运行的对话中很有用.另一方面,在具有扩展的Session上下文的长时间对话中,save方法并不好.

  • Hibernate中的save和persist方法之间的第五个区别:JPA支持persist,而只有Hibernate支持save.

您可以在Hibernate中看到保存和持久方法之间差异的完整工作示例


小智 5

save() - 正如方法名称所示,hibernate save()可用于将实体保存到数据库.我们可以在事务外调用此方法.如果我们在没有事务的情况下使用它,并且我们在实体之间进行级联,那么除非我们刷新会话,否则只保存主实体.

persist() - Hibernate persist类似于save(with transaction),它将实体对象添加到持久化上下文中,因此跟踪任何进一步的更改.如果在提交事务或刷新会话之前更改了对象属性,则它也将保存到数据库中.此外,我们只能在事务的边界内使用persist()方法,因此它是安全的并且可以处理任何级联对象.最后,persist不返回任何内容,因此我们需要使用持久化对象来获取生成的标识符值.


Moh*_*men 5

区别在于:

  1. 保存:

    1. 将对象保存到数据库时,将返回ID /标识符。
    2. 当对象在分离后通过打开新会话尝试执行相同操作时,也将保存。
  2. 坚持:

    1. 将对象保存到数据库时将返回void。
    2. 尝试通过新会话保存分离的对象时,将抛出PersistentObjectException。