在Hibernate中persist()vs save()的优点是什么?
任何人都可以告诉我什么是persist()
vs save()
在hibernate的优点?
从这个论坛post
persist()
已经定义好了。 它使一个瞬态实例持久。 但是,不能保证标识符值将立即分配给持久实例,分配可能在刷新时发生。 规范没有说,这是我persist()
。
persist()
还保证,如果在事务边界之外调用,它将不执行INSERT语句。 这在长时间的会话/持久性上下文的会话中很有用。像
persist()
这样的方法是必需的。
save()
不能保证是相同的,它会返回一个标识符,并且如果必须执行一个INSERT来获得标识符(例如“identity”生成器,而不是“sequence”),这个INSERT立即发生,不pipe你在里面或在交易之外。 这与扩展的会话/持久性上下文的长时间对话中不太好。
我对save()vs persist()做了很好的研究,包括在我的本地机器上多次运行它。 所有以前的解释都是混乱的,不正确的。 我在彻底的研究之后比较了save()和persist()。
Save()
- 保存后返回生成的ID。 它的
Serializable
返回types。 - 直接将值保存到数据库,并跟踪实体,直到会话结束(我尝试更改事务外的实体值,但在会话提交时不显示任何效果)
- 不会将更改保存到事务外部的数据库。
- 将生成的标识分配给您所持有的实体
- 一个分离的对象的Session.save()将在表中创build一个新的行。
Persist()
- 保存后不返回生成的ID。 它的void返回types。
- 将值保存到数据库,并跟踪实体,直到会话结束(我试图改变事务外的实体值,当会话提交时不显示任何效果)
- 不会将更改保存到事务外部的数据库。
- 将
generated id
分配给您所持有的实体 -
session.persist()
对于分离的对象将抛出PersistentObjectException
因为它是不允许的。
所有这些都在Hibernate v4.0.1
上进行过testing/testing。
我做了一些模拟testing来loggingsave()
和persist()
之间的区别。
听起来像这两个方法在处理瞬态实体时performance相同,但在处理分离实体时有所不同。
对于下面的示例,将EmployeeVehicle作为一个实体,将PK作为vehicleName
(生成值和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') // This is for vehicle Id generated : 36 insert into Employee_Vehicle ( Vehicle_Name, Vehicle_Id) values ( Honda, 36)
注意,当你得到一个已经存在的对象并保存时,结果是一样的
EmployeeVehicle entity = (EmployeeVehicle)session.get(EmployeeVehicle.class, 36); entity.setVehicleName("Toyota"); session.save(entity); -------> **instead of session.update(entity);** // session.persist(entity);
使用persist(entity)
重复相同的操作,结果与新的ID(比如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的车辆名称更新为“丰田”。 但是会发生什么是一个新的实体被保存在数据库中,新名称为“丰田”
select nextval ('hibernate_sequence') insert into Employee_Vehicle ( Vehicle_Name, Vehicle_Id) values ( Toyota, 39)
坚持坚持独立实体
// (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();
结果:
Exception being thrown : detached entity passed to persist
因此,使用Persist()而不是Save()作为保存时总是要小心处理Transient对象。
重要提示:在上面的例子中,vehicle实体的pk是一个生成的值,所以当使用save()来持久化一个分离的实体时,hibernate会生成一个新的id来保存。 但是,如果这个pk不是一个生成的值,那么它将导致一个违反的键。
这个问题有一些关于Hibernate中不同持久化方法的很好的答案。 要直接回答您的问题,使用save(),无论事务状态如何,插入语句都会立即执行。 它返回插入的键,所以你可以做这样的事情:
long newKey = session.save(myObj);
因此,如果您需要立即将标识符分配给持久性实例,请使用save()。
使用persist(),插入语句在事务中执行,不一定立即执行。 这在大多数情况下是可取的。
使用persist()如果你不需要插入与事务不顺序发生,你不需要返回插入的键。
save() – 如方法名称所示,可以使用hibernate save()将实体保存到数据库。 我们可以在事务之外调用这个方法。 如果我们在没有事务的情况下使用它,并且在实体之间有级联,那么除非我们刷新会话,否则只有主实体被保存。
persist() – Hibernate persist与save(使用事务)类似,它将实体对象添加到持久化上下文,所以进一步的更改被跟踪。 如果在提交事务或刷新会话之前更改对象属性,则也将其保存到数据库中。 而且,我们只能在事务的边界内使用persist()方法,所以它是安全的并且处理任何级联的对象。 最后,persist不会返回任何东西,所以我们需要使用持久化对象来获取生成的标识符值。
实际上,hibernate save()和persist()方法的区别取决于我们使用的生成器类。
如果我们的生成器类被赋值,那么save()和persist()方法之间没有区别。 因为发生器的赋值意味着,作为一个程序员,我们需要给出主键值来保存在数据库中[希望你知道这个发生器的概念]如果不是指定的发生器类,假设我们的发生器类名称是Incrementhibernate它自己会分配主键ID值到数据库的权利[除了分配的发电机,hibernate只用于照顾的主键ID值记住],所以在这种情况下,如果我们调用save()或persist()方法然后它会将logging正常插入到数据库中
但是听到的是,save()方法可以返回由hibernate生成的主键id值,我们可以看到它
long s = session.save(k);
在这种情况下,persist()永远不会给客户端返回任何值,返回void。
persist()还保证,如果在事务边界之外调用,它将不执行INSERT语句。
Save()INSERT立即发生,不pipe你是在一个事务之内还是之外。
以下是帮助您获得持久保存方法的差异:
- 保存和保持的第一个区别是返回types。 保存方式的返回types是无效的
方法是Serializable对象。 -
persist()方法不保证将标识符值立即分配到持久状态,分配可能发生在刷新时间。
-
如果在事务边界之外调用persist()方法,则不会执行插入查询。 而save()方法返回一个标识符,以便立即执行插入查询来获取标识符,而不pipe它是在事务之内还是之外。
-
persist方法在事务边界之外被调用,它在具有扩展的Session上下文的长时间运行的对话中是有用的。 另一方面,保存方法在长时间与扩展会话上下文的会话中是不好的。
-
Hibernate中保存和持久化方法的第五个区别:JPA支持persist,而Hibernate只支持保存。
你可以从后面的Hibernate中的保存和持久化方法之间的区别看到完整的工作示例
基本规则说:
对于生成标识符的实体:
save():除了使对象持久化之外,它立即返回实体的标识符。 所以插入查询立即被激发。
persist():它返回持久化对象。 它没有任何强制立即返回标识符,因此不能保证插入将立即被触发。 它可能会立即触发插入,但不能保证。 在某些情况下,可能会立即触发查询,而在其他情况下,可能会在会话刷新时触发查询。
对于分配有标识符的实体:
save():立即返回一个实体的标识符。 由于标识符在调用保存之前已经被分配给实体,所以插入不会立即被触发。 在会话刷新时间被触发。
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; } }
保存() :
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();
persist():
Session session = sessionFactory.openSession(); session.beginTransaction(); UserDetails user = new UserDetails(); user.setUserName("Gaurav"); session.save(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();
现在假设我们有如下定义的相同的实体,但没有生成注释的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; } }
对于save():
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();
for 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();
上述情况在事务处理中保存或保留时被调用。
保存和保存的区别点在于:
-
save()可以在事务外被调用。 如果使用分配的标识符,则由于id已经可用,所以不会立即触发插入查询。 该查询仅在会话刷新时触发。
-
如果使用生成的标识符,那么由于id需要生成,插入立即被触发。 但它只保存了主要实体。 如果实体有一些级联的实体,那么这些将不会保存在数据库中。 当会话被刷新时,它们将被保存。
-
如果persist()在事务之外,那么只有在会话被刷新时插入才会被触发,而不pipe使用什么样的标识符(生成或分配)。
-
如果通过持久对象调用保存,则使用更新查询保存该实体。
以下是区别:
-
保存:
- 将对象保存到数据库时将返回标识符/标识符。
- 当对象被分离后打开一个新的会话时也会保存。
-
坚持:
- 将对象保存到数据库时将返回void。
- 尝试通过新会话保存分离的对象时会抛出PersistentObjectException。
- 用Hibernate + Spring进行caching – 一些问题!
- load()vs get()在Hibernate中的优点是什么?
- 不区分大小写等于使用Hibernate标准
- 我如何从jackson的一个自定义反序列化器中调用默认的反序列化器
- hibernate问题 – “使用@OneToMany或@ManyToMany定位未映射的类”
- Hibernate的两个configuration文件的目的是什么?
- Hibernate 4.1Final替代Hibernate.STRING
- org.hibernate.Query中的setMaxResults和setFetchSize有什么区别?
- hibernate错误:具有相同标识符值的不同对象已经与会话相关联