hibernate之使用脱管对象(合并脱管对象的状态)
脱管对象的合并是另一种可以选择的方法。它可以是重附的补充。也可以取代重附。合并最初引入到hibernate中,是用来处理重附无法再满足的特殊案例,看看下列代码,试着重附一个脱管对象:
上述代码给定了一个包含数据库同一性的脱管item对象。修改它之后,你尝试把它重附到一个新的Session。但在重附之前,另一个表示相同数据库行的实例已经被加载到了这个session的持久化上下文中。显然,通过update()进行的重附与这个已经持久化的实例相抵触,抛出NonuniqueObjectException。异常的错误信息为:persistent instancewith the same database identifier is already associated with the Session!(包含相同数据库标识符的持久化实例已经与会话关联!)Hibernate无法确定哪个对象表示当前状态。
可以先通过重附item解决这种情况;然后,由于对象处于持久化状态,无需获取item2。在像这个例子一样简单的代码中,这很容易理解,但是它或许不可能在更为复杂的应用程序中进行重构。毕竟,客户端把脱管对象发送到了持久层让它变成托管,并且客户端可能不(且不应该)知道已经处于持久化上下文中的托管实例。
再看下例:
merge()调用导致了几个动作。第一,hibernate检查持久化上下文中的持久化实例是否具有与正在合并的脱管实例相同的数据库标识符。在上个例子中,答案是肯定的,item和item2都用get()得到加载,它们具有相同的主键值。
1. 如果持久化上下文中有相等的持久化实例,hibernate把脱管实例的状态复制到持久化实例中去。换句话说,已经在脱管item上设置新描述也设置在了持久化item2上。
2. 如果持久化上下文中没有相等的持久化实例,hibernate就从数据库中加载它(就像你用get()所做的那样,通过标识符有效地执行相同的获取),然后把脱管状态与被获取的对象的状态合并。
3. 如果持久化上下文中没有相等的持久化实例,并且在数据库中的查找没有结果,就会创建新的持久化实例,并且把被合并的实例的状态复制到新实例中。然后就计划把这个新对象插入到数据库中,并通过merge()操作返回。
4. 如果传到merge()里面的实例是一个瞬时实例,而不是脱管对象时,也会发生插入。
------------------
实例1:
如果持久化上下文中有相等的持久化实例,hibernate把脱管实例的状态复制到持久化实例中去。换句话说,已经在脱管user上设置name也设置在了持久化user2上。
输出日志:
-------------------
实例2:
如果持久化上下文中没有相等的持久化实例,hibernate就从数据库中加载它(就像你用get()所做的那样,通过标识符有效地执行相同的获取),然后把脱管状态与被获取的对象的状态合并。
输出日志:
--------------------
实例3:
3. 如果持久化上下文中没有相等的持久化实例,并且在数据库中的查找没有结果,就会创建新的持久化实例,并且把被合并的实例的状态复制到新实例中。然后就计划把这个新对象插入到数据库中,并通过merge()操作返回。
4. 如果传到merge()里面的实例是一个瞬时实例,而不是脱管对象时,也会发生插入。
输出日志: