1、save
1)返回值
Serializable
2)事件监听处理类及重要代码
DefaultSaveEventListener
public
class
DefaultSaveEventListener
extends
DefaultSaveOrUpdateEventListener {
protected
Serializable performSaveOrUpdate(SaveOrUpdateEvent event) {
// this implementation is supposed to tolerate incorrect unsaved-value
// mappings, for the purpose of backward-compatibility
EntityEntry entry = event.getSession().getPersistenceContext().getEntry( event.getEntity() );
if
( entry!=
null
&& entry.getStatus() != Status.
DELETED
) { //这里将游离态实体当做瞬时态再插入一遍
return
entityIsPersistent(event);
}
else
{
return
entityIsTransient(event);
}
}
}
3)事务范围外的处理方式
3.1)Connection设置事务为自动提交时,
且ID由数据库自动生成的,save会
立即执行插入操作,并自动提交事务,数据库中有数据;
3.2)Connection设置事务为
非自动提交时,
且ID由数据库自动生成的,如果不手动开启/提交事务,save操作会
立即执行,但是不会提交事务,所以数据库没有数据。
如果手动开启事务/提交事务,save操作会
立即执行,当提交事务时,将更新提交至数据库。
4)游离态
如果一个游离态的实体,再次使用save方法,将不会更新原来的对象,只会在数据库中重新再插入一条,执行规则遵循3.1)和 3.2)。
5)持久态
如果一个持久态的实体,再次使用save方法,将不会执行数据库操作,只会做一些数据验证,并返回唯一ID。
6)瞬时态
如果一个瞬时态的实体,执行save方法,将会在数据库中插入一条记录。
7)总结
7.1)save不区分游离态和瞬时态,它把游离态作为瞬时态处理。
7.2)如果ID列不是由数据库自动生成的,而是由编程管理并生成的(不管是手动赋值Assigned,还是使用UUID,GUID等策略),save操作都会不立即执行。
7.3)只有
EntityIdentityInsertAction才有可能
不
会延迟执行,
EntityInsertAction永远都是延迟执行的。
迟延执行指的是手动提交事务才到数据
库执行,无事务情况下就没办法提交更新了。
源码:
private
AbstractEntityInsertAction addInsertAction(
Object[] values,
Serializable id,
Object entity,
EntityPersister persister,
boolean
useIdentityColumn,
EventSource source,
boolean
shouldDelayIdentityInserts) {
if
( useIdentityColumn ) {
EntityIdentityInsertAction insert =
new
EntityIdentityInsertAction(
values, entity, persister, isVersionIncrementDisabled(), source, shouldDelayIdentityInserts
);
source.getActionQueue().addAction( insert );
return
insert;
//
EntityIdentityInsertAction 有可能为true
//
public
boolean
isEarlyInsert () {
//
return
!
isDelayed
;
// }
}
else
{
Object version = Versioning. getVersion( values, persister );
EntityInsertAction insert =
new
EntityInsertAction(
id, values, entity, version, persister, isVersionIncrementDisabled(), source
);
source.getActionQueue().addAction( insert );
return
insert;
//
EntityInsertAction 永远返回false
//
public
boolean
isEarlyInsert() {
//
return
false
;
// }
}
}
2、update
1)返回值
void
2)事件监听处理类及重要代码
DefaultUpdateEventListener
protected
Serializable performSaveOrUpdate(SaveOrUpdateEvent event) {
// this implementation is supposed to tolerate incorrect unsaved-value
// mappings, for the purpose of backward-compatibility
EntityEntry entry = event.getSession().getPersistenceContext().getEntry( event.getEntity() );
if
( entry!=
null
) {
if
( entry.getStatus()== Status.DELETED ) {
throw
new
ObjectDeletedException(
"deleted instance passed to update()"
,
null
, event.getEntityName() );
}
else
{
return
entityIsPersistent(event);
}
}
else
{
entityIsDetached(event);
return
null
;
}
}
3)事务范围外的处理方式
非立即执行
4)瞬时态
注意上面代码,没有瞬时态的处理部分,瞬时态被当做游离态处理,执行
entityIsDetached
(event)方法;
结果是如果update一个瞬时态的对象,提交事务时,数据库中
是不会执行插入操作(insert)的,执行的还是更新操作(update),所以会抛出异常。因为
entityIsDetached
(event)方法会将瞬时态转为持久态,但是该数据在数据库中
是不存在的,update操作期望更新一条记录,但是更新返回的结果却是0,所以程序将会抛出异常。
5)游离态
update只是将瞬时态转为持久态或游离态转为持久态,并在
PersistenceContext持久化上下文中加入EntityEntry;只有等到提交事务时,
执行Flush
操作,才会从
PersistenceContext中将所有需要更新的实体,为之
在ActionQueue中
添加相应的
更新操作(Entity
UpdateAction)
,然后依次执行。
6)持久态
如果一个持久态的实体,将不会执行数据库操作,只会做一些数据验证,并返回唯一ID。
7)总结
7.1)更新操作不会插入数据
7.2)更新操作不会立即执行
3、saveOrUpdate
1) 返回值
void
2)事件监听处理类及重要代码
DefaultSaveOrUpdateEventListener
protected
Serializable performSaveOrUpdate(SaveOrUpdateEvent event) {
EntityState entityState = getEntityState(
event.getEntity(),
event.getEntityName(),
event.getEntry(),
event.getSession()
);
switch
( entityState ) {
case
DETACHED:
entityIsDetached( event );
return
null
;
case
PERSISTENT:
return
entityIsPersistent( event );
default
:
//TRANSIENT or DELETED
return
entityIsTransient( event );
}
}
3)事务范围外的处理方式
由于
saveOrUpdate方法与save方法的相似性,
所以是否立即执行或者事务管理方面是一样的。见save方法。
4) 瞬时态
与save方法一致。
5)游离态
与update方法一致。
6)持久态
与save方法一致。
7)总结
7.1) save方法存在一个问题:save游离态实体时,不会更新数据库中相应的对象,而是重新插入一条记录;因为save将游离态看做瞬时态;
7.2) update方法存在一个问题:update瞬时态实体时,不会在数据库中插入一条数据,而是会抛出异常;因为update将瞬时态看做游离态,
数据库中并没有与之相应的数据记录,
只是在持久化上下文中将该
实体看做持久态,等到事务提交时,本来希望更新数据库一条
记录,
实际上更新的结果为0,所以会抛出异常。
7.3) 正是由于save和update方法存在的问题,所以saveOrUpdate方法解决了上述两个方法存在的问题。saveOrUpdate将对实体状态进行细分,
分为游离态、持久态、瞬时态;所以游离态不会被当做瞬时态处理,执行真正的update方法,而不是save方法;瞬时态也不会被当做游离态处理,
执行真正的save方法,而不是update方法。
7.4)从本质上说(代码的角度),saveOrUpdate方法与save方法的处理逻辑是基本一致的,只是对待实体状态时的区分逻辑有所不同;
saveOrUpdate将实体状态
分为
游离态、持久态、瞬时态,并做相应的处理,以便更正确的执行相应操作;
save只分为持久态和瞬时态,将游离态看做的瞬时态,所以
这是
save
方法
导致问题的根本所在。
7.5)正是由于
saveOrUpdate方法与save方法的相似性,
所以是否立即执行或者事务管理方面是一样的。见save方法。