Hibernate源码节选(二)save、update与saveOrUpdate

本文基于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

发布了10 篇原创文章 · 获赞 1 · 访问量 6824

猜你喜欢

转载自blog.csdn.net/jakekong/article/details/105339593