本文基于Hibernate 5.2
Session的save、update、saveOrUpdate
- Session#save
熟悉的操作:创建一个事件,找出对save事件感兴趣的监听器,把事件交给它们
public Serializable save(String entityName, Object object) throws HibernateException {
return fireSave( new SaveOrUpdateEvent( entityName, object, this ) );
}
private Serializable fireSave(SaveOrUpdateEvent event) {
checkOpen();
checkTransactionSynchStatus();
checkNoUnresolvedActionsBeforeOperation();
for ( SaveOrUpdateEventListener listener : listeners( EventType.SAVE ) ) {
listener.onSaveOrUpdate( event );//把事件交给监听器
}
checkNoUnresolvedActionsAfterOperation();
return event.getResultId();//update和saveOrUpdate不会返回id
}
listeners( EventType.SAVE ) 的作用是返回对 EventType.SAVE 感兴趣的监听器
类似的,update和saveOrUpdate分别使用EventType.UPDATE和EventType.SAVE_UPDATE
SaveOrUpdateEventListener
在开始研究监听器怎么处理事件之前,先看看这三个监听器:
DefaultSaveOrUpdateEventListener
DefaultSaveEventListener
DefaultUpdateEventListener
就像它们的名字一样,三种监听器分别对应三种情况。另外,后两个监听器继承自第一个监听器,重写逻辑差异部分,至于其他功能用父类已经写好的实现就可以了。
- DefaultSaveOrUpdateEventListener#onSaveOrUpdate
正如前面说过的,三个监听器的onSaveOrUpdate都是共用DefaultSaveOrUpdateEventListener已有的实现
public void onSaveOrUpdate(SaveOrUpdateEvent event) {
final SessionImplementor source = event.getSession();
final Object object = event.getObject();
final Serializable requestedId = event.getRequestedId();
if ( requestedId != null ) {
//assign the requested id to the proxy, *beforeQuery*
//reassociating the proxy
if ( object instanceof HibernateProxy ) {
( (HibernateProxy) object ).getHibernateLazyInitializer().setIdentifier( requestedId );
}
}
// For an uninitialized proxy, noop, don't even need to return an id, since it is never a save()
if ( reassociateIfUninitializedProxy( object, source ) ) {
LOG.trace( "Reassociated uninitialized proxy" );
}
else {
//initialize properties of the event:
//取出代理里面的实体
final Object entity = source.getPersistenceContext().unproxyAndReassociate( object );
event.setEntity( entity );
event.setEntry( source.getPersistenceContext().getEntry( entity ) );
//return the id in the event object
//从这里开始,要区分save、update、saveOrUpdate了
event.setResultId( performSaveOrUpdate( event ) );
}
}
save
- DefaultSaveEventListener#performSaveOrUpdate
两个分支:
1.持久态
2.瞬时态和游离态,后者被当成瞬时态处理
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);//分支1,持久态
}
else {
return entityIsTransient(event);//分支2,瞬时态和游离态
}
}
}
对于持久态实体的保存,只做校验,并不会与数据库交互。
protected Serializable entityIsPersistent(SaveOrUpdateEvent event) throws HibernateException {
......
EntityEntry entityEntry = event.getEntry();
if ( entityEntry == null ) {
throw new AssertionFailure( "entity was transient or detached" );
}
else {
if ( entityEntry.getStatus() == Status.DELETED ) {
throw new AssertionFailure( "entity was deleted" );
}
final SessionFactoryImplementor factory = event.getSession().getFactory();
Serializable requestedId = event.getRequestedId();
Serializable savedId;
if ( requestedId == null ) {
savedId = entityEntry.getId();
}
else {
final boolean isEqual = !entityEntry.getPersister().getIdentifierType()
.isEqual( requestedId, entityEntry.getId(), factory );
if ( isEqual ) {
throw new PersistentObjectException(
"object passed to save() was already persistent: " +
MessageHelper.infoString( entityEntry.getPersister(), requestedId, factory )
);
}
savedId = requestedId;
}
......
return savedId;
}
}
对于瞬时态的保存,先生成id,然后生成保存队列。
id生成部分借用一下别人的结论
uuid:有对应的java类实现
guid:使用SQL语句”select uuid()“
increment:由hibernate同步控制 “select max(” + column + ") from ",如果所有increment都由hibernate控制,那就没有并发问题
foreign key:使用关联的对象的id
Identity:数据库提供的自增,需要插入数据库后才能获得。hibernate的做法是给一个特殊id,插入完后再获取
protected Serializable saveWithGeneratedId(
Object entity,
String entityName,
Object anything,
EventSource source,
boolean requiresImmediateIdAccess) {
......
EntityPersister persister = source.getEntityPersister( entityName, entity );
Serializable generatedId = persister.getIdentifierGenerator().generate( source, entity );
if ( generatedId == null ) {
throw new IdentifierGenerationException( "null id generated for:" + entity.getClass() );
}
else if ( generatedId == IdentifierGeneratorHelper.SHORT_CIRCUIT_INDICATOR ) {
//特殊处理 使用外键id的数据可能会提前插入,直接返回
return source.getIdentifier( entity );
}
else if ( generatedId == IdentifierGeneratorHelper.POST_INSERT_INDICATOR ) {
//特殊处理 数据库自增长id,需要插入后才能获得id
return performSave( entity, null, persister, true, anything, source, requiresImmediateIdAccess );
}
else {
......
//一般情况
return performSave( entity, generatedId, persister, false, anything, source, true );
}
}
protected Serializable performSave(
Object entity,
Serializable id,
EntityPersister persister,
boolean useIdentityColumn,
Object anything,
EventSource source,
boolean requiresImmediateIdAccess) {
......
final EntityKey key;
if ( !useIdentityColumn ) { //id在数据库插入前已经得到
key = source.generateEntityKey( id, persister );
......
}
else { // id需要数据库插入后才能得到
key = null;
}
......
return performSaveOrReplicate( entity, key, persister, useIdentityColumn, anything, source, requiresImmediateIdAccess );
}
protected Serializable performSaveOrReplicate(
Object entity,
EntityKey key,
EntityPersister persister,
boolean useIdentityColumn,
Object anything,
EventSource source,
boolean requiresImmediateIdAccess) {
Serializable id = key == null ? null : key.getIdentifier();
boolean inTxn = source.isTransactionInProgress();
boolean shouldDelayIdentityInserts = !inTxn && !requiresImmediateIdAccess;
// Put a placeholder in entries, so we don't recurse back and try to save() the
// same object again. QUESTION: should this be done beforeQuery onSave() is called?
// likewise, should it be done beforeQuery onUpdate()?
EntityEntry original = source.getPersistenceContext().addEntry(
entity,
Status.SAVING,
null,
null,
id,
null,
LockMode.WRITE,
useIdentityColumn,
persister,
false
);
......
//加入到插入队列,等到flush的时候将会刷出
//对于Identity,则会立刻刷出
AbstractEntityInsertAction insert = addInsertAction(
values, id, entity, persister, useIdentityColumn, source, shouldDelayIdentityInserts );
......
//对于Identity,还要从返回结果中获取id
if ( useIdentityColumn && insert.isEarlyInsert() ) {
if ( !EntityIdentityInsertAction.class.isInstance( insert ) ) {
throw new IllegalStateException(
"Insert should be using an identity column, but action is of unexpected type: " +
insert.getClass().getName()
);
}
id = ((EntityIdentityInsertAction) insert).getGeneratedId();
insert.handleNaturalIdPostSaveNotifications( id );
}
......
return id;
}
游离态的保存和瞬时态一样,会插入一条新数据。
update
两个分支:
1.持久态:只是做校验,不会和数据库交互。见save的持久态分支
2.游离态:和数据库做update操作。瞬时态也会进入该分支,但由于在数据库中没有记录会导致报错
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);// 分支1,持久态
}
}
else {
entityIsDetached(event);//分支2,游离态
return null;
}
}
update 游离态
protected void entityIsDetached(SaveOrUpdateEvent event) {
if ( event.getSession().getPersistenceContext().isEntryFor( event.getEntity() ) ) {
//TODO: assertion only, could be optimized away
throw new AssertionFailure( "entity was persistent" );
}
Object entity = event.getEntity();
EntityPersister persister = event.getSession().getEntityPersister( event.getEntityName(), entity );
event.setRequestedId(
getUpdateId(
entity, persister, event.getRequestedId(), event.getSession()
)
);
performUpdate( event, entity, persister );
}
转化成持久态,加入到EntityEntry中,在Session.flush刷出
protected void performUpdate(
SaveOrUpdateEvent event,
Object entity,
EntityPersister persister) throws HibernateException {
......
final EventSource source = event.getSession();
final EntityKey key = source.generateEntityKey( event.getRequestedId(), persister );
source.getPersistenceContext().checkUniqueness( key, entity );
if ( invokeUpdateLifecycle( entity, persister, source ) ) {
reassociate( event, event.getObject(), event.getRequestedId(), persister );
return;
}
// this is a transient object with existing persistent state not loaded by the session
new OnUpdateVisitor( source, event.getRequestedId(), entity ).process( entity, persister );
//将游离态转化成持久态,加入到EntityEntry中,将在Session.flush刷出
source.getPersistenceContext().addEntity(
entity,
( persister.isMutable() ? Status.MANAGED : Status.READ_ONLY ),
null, // cachedState,
key,
persister.getVersion( entity ),
LockMode.NONE,
true,
persister,
false
);
persister.afterReassociate( entity, source );
......
cascadeOnUpdate( event, persister, entity );
}
saveOrUpdate
protected Serializable performSaveOrUpdate(SaveOrUpdateEvent event) {
EntityState entityState = getEntityState(
event.getEntity(),
event.getEntityName(),
event.getEntry(),
event.getSession()
);
switch ( entityState ) {
case DETACHED:
entityIsDetached( event );//游离态 update
return null;
case PERSISTENT:
return entityIsPersistent( event );// 持久态 save
default: //TRANSIENT or DELETED
return entityIsTransient( event );// 瞬时态或已删除 save
}
}
结论
save
持久态:只做校验,不与数据库交互
瞬时态:分配id,加入到保存操作队列,在flush时INSERT到数据库中。(如果id需要插入后才能获得,那么会跳过队列INSERT到数据库中)
游离态:同瞬时态,最终导致INSERT一条数据
update
持久态:只做校验,不与数据库交互(save)
瞬时态:走游离态的逻辑,但会报错
游离态:转化为持久态,同时加入到EntityEntry中,在flush时UPDATE到数据库中
saveOrUpdate
持久态:save
瞬时态:save
游离态:update