Hibernate有一些方法,它们以某种方式获取对象并将其放入数据库中。它们之间的区别是什么,什么时候使用哪个,为什么没有一种智能方法知道什么时候使用什么?

到目前为止,我已经确定的方法是:

save () (更新) saveOrUpdate () saveOrUpdateCopy () 合并() persist ()


当前回答

上面的答案都不完整。虽然Leo Theobald的答案看起来很接近。

基本要点是hibernate如何处理实体的状态,以及当状态发生变化时如何处理它们。所有的事情都必须考虑到刷新和提交,而每个人似乎都完全忽略了这一点。

不要使用HIBERNATE的保存方法。忘记它甚至存在于冬眠!

坚持

正如大家所解释的,持久化基本上是将一个实体从“瞬态”状态转换为“托管”状态。此时,slush或commit可以创建插入语句。但实体仍将保持“托管”状态。它不随同花顺而改变。

在这一点上,如果你再次“坚持”,将不会有任何改变。如果我们试图持久化一个持久化实体,就不会有更多的保存。

当我们试图驱逐实体时,乐趣就开始了。

驱逐是Hibernate的一个特殊功能,它将实体从“托管”转换为“分离”。不能在分离实体上调用持久化。如果我们这样做,那么Hibernate将引发一个异常,整个事务将在提交时回滚。

合并与更新

这是两个有趣的函数,用不同的方法处理会产生不同的效果。它们都试图将实体从“分离”状态转换为“托管”状态。但是用不同的方式。

理解一个事实,即Detached意味着一种“脱机”状态。managed表示“在线”状态。

观察下面的代码:

Session ses1 = sessionFactory.openSession();

    Transaction tx1 = ses1.beginTransaction();

    HibEntity entity = getHibEntity();

    ses1.persist(entity);
    ses1.evict(entity);

    ses1.merge(entity);

    ses1.delete(entity);

    tx1.commit();

当你这样做的时候?你认为会发生什么? 如果你说这会引起异常,那么你是正确的。这将引发异常,因为合并已经对实体对象进行了操作,该实体对象处于分离状态。但它不会改变对象的状态。

在后台,merge将引发一个选择查询,并返回一个处于附加状态的实体副本。观察下面的代码:

Session ses1 = sessionFactory.openSession();

    Transaction tx1 = ses1.beginTransaction();
    HibEntity entity = getHibEntity();

    ses1.persist(entity);
    ses1.evict(entity);

    HibEntity copied = (HibEntity)ses1.merge(entity);
    ses1.delete(copied);

    tx1.commit();

上面的示例之所以有效,是因为merge将一个新的实体带入了处于持久状态的上下文中。

当与Update一起应用时,同样的工作很好,因为Update实际上不像merge那样带来实体的副本。

Session ses1 = sessionFactory.openSession();

    Transaction tx1 = ses1.beginTransaction();

    HibEntity entity = getHibEntity();

    ses1.persist(entity);
    ses1.evict(entity);

    ses1.update(entity);

    ses1.delete(entity);

    tx1.commit();

同时在调试跟踪中,我们可以看到Update并没有引发像merge这样的select SQL查询。

删除

在上面的例子中,我使用了delete而没有谈论delete。Delete基本上会将实体从托管状态转换为“已删除”状态。当刷新或提交时,将发出删除命令来存储。

然而,使用persist方法可以将实体从“已删除”状态带回“已管理”状态。

希望以上解释澄清了您的疑问。

其他回答

实际上,hibernate save()和persist()方法之间的区别取决于我们使用的生成器类。

If our generator class is assigned, then there is no difference between save() and persist() methods. Because generator ‘assigned’ means, as a programmer we need to give the primary key value to save in the database right [ Hope you know this generators concept ] In case of other than assigned generator class, suppose if our generator class name is Increment means hibernate it self will assign the primary key id value into the database right [ other than assigned generator, hibernate only used to take care the primary key id value remember ], so in this case if we call save() or persist() method then it will insert the record into the database normally But hear thing is, save() method can return that primary key id value which is generated by hibernate and we can see it by

long s = session.save(k);

在同样的情况下,persist()将永远不会向客户端返回任何值。

上面的答案都不完整。虽然Leo Theobald的答案看起来很接近。

基本要点是hibernate如何处理实体的状态,以及当状态发生变化时如何处理它们。所有的事情都必须考虑到刷新和提交,而每个人似乎都完全忽略了这一点。

不要使用HIBERNATE的保存方法。忘记它甚至存在于冬眠!

坚持

正如大家所解释的,持久化基本上是将一个实体从“瞬态”状态转换为“托管”状态。此时,slush或commit可以创建插入语句。但实体仍将保持“托管”状态。它不随同花顺而改变。

在这一点上,如果你再次“坚持”,将不会有任何改变。如果我们试图持久化一个持久化实体,就不会有更多的保存。

当我们试图驱逐实体时,乐趣就开始了。

驱逐是Hibernate的一个特殊功能,它将实体从“托管”转换为“分离”。不能在分离实体上调用持久化。如果我们这样做,那么Hibernate将引发一个异常,整个事务将在提交时回滚。

合并与更新

这是两个有趣的函数,用不同的方法处理会产生不同的效果。它们都试图将实体从“分离”状态转换为“托管”状态。但是用不同的方式。

理解一个事实,即Detached意味着一种“脱机”状态。managed表示“在线”状态。

观察下面的代码:

Session ses1 = sessionFactory.openSession();

    Transaction tx1 = ses1.beginTransaction();

    HibEntity entity = getHibEntity();

    ses1.persist(entity);
    ses1.evict(entity);

    ses1.merge(entity);

    ses1.delete(entity);

    tx1.commit();

当你这样做的时候?你认为会发生什么? 如果你说这会引起异常,那么你是正确的。这将引发异常,因为合并已经对实体对象进行了操作,该实体对象处于分离状态。但它不会改变对象的状态。

在后台,merge将引发一个选择查询,并返回一个处于附加状态的实体副本。观察下面的代码:

Session ses1 = sessionFactory.openSession();

    Transaction tx1 = ses1.beginTransaction();
    HibEntity entity = getHibEntity();

    ses1.persist(entity);
    ses1.evict(entity);

    HibEntity copied = (HibEntity)ses1.merge(entity);
    ses1.delete(copied);

    tx1.commit();

上面的示例之所以有效,是因为merge将一个新的实体带入了处于持久状态的上下文中。

当与Update一起应用时,同样的工作很好,因为Update实际上不像merge那样带来实体的副本。

Session ses1 = sessionFactory.openSession();

    Transaction tx1 = ses1.beginTransaction();

    HibEntity entity = getHibEntity();

    ses1.persist(entity);
    ses1.evict(entity);

    ses1.update(entity);

    ses1.delete(entity);

    tx1.commit();

同时在调试跟踪中,我们可以看到Update并没有引发像merge这样的select SQL查询。

删除

在上面的例子中,我使用了delete而没有谈论delete。Delete基本上会将实体从托管状态转换为“已删除”状态。当刷新或提交时,将发出删除命令来存储。

然而,使用persist方法可以将实体从“已删除”状态带回“已管理”状态。

希望以上解释澄清了您的疑问。

See the Hibernate Forum for a explanation of the subtle differences between persist and save. It looks like the difference is the time the INSERT statement is ultimately executed. Since save does return the identifier, the INSERT statement has to be executed instantly regardless of the state of the transaction (which generally is a bad thing). Persist won't execute any statements outside of the currently running transaction just to assign the identifier. Save/Persist both work on transient instances, ie instances which have no identifier assigned yet and as such are not saved in the DB. Update and Merge both work on detached instances, ie instances which have a corresponding entry in the DB but which are currently not attached to (or managed by) a Session. The difference between them are what happens to the instance which is passed to the function. update tries to reattach the instance, that means that there must be no other instance of the persistent entity attached to the Session right now, otherwise an exception is thrown. merge, however, just copies all values to a persistent instance in the Session (which will be loaded if it is not currently loaded). The input object is not changed. So merge is more general than update, but may use more resources.

以下是我对这些方法的理解。这些主要是基于API的,尽管我在实践中没有使用所有这些。

saveOrUpdate 根据某些检查调用save或update。例如,如果不存在标识符,则调用save。否则调用update。

保存 持久化一个实体。如果标识符不存在,将分配标识符。如果有,它本质上是在进行更新。返回生成的实体ID。

更新 尝试使用现有标识符持久化实体。如果不存在标识符,则抛出异常。

saveOrUpdateCopy 这已弃用,不应再使用。取而代之的是……

合并 现在我的知识开始动摇了。这里重要的是瞬态实体、分离实体和持久实体之间的区别。有关对象状态的更多信息,请查看这里。使用save & update,你处理的是持久对象。它们被链接到一个会话,因此Hibernate知道发生了什么变化。但是当你有一个瞬态对象时,就不涉及会话了。在这些情况下,您需要使用合并进行更新,使用持久化进行保存。

坚持 如上所述,这用于瞬态对象。它不返回生成的ID。

请注意,如果对已分离对象调用更新,无论是否更改对象,数据库中总是会完成更新。如果不是你想要的,你应该使用Session.lock()和LockMode.None。

只有当对象在当前会话范围之外被更改时(当处于分离模式时),才应该调用update。