Hibernate 专题研究系列(一) save/update/saveOrUpdate等方法学习(续一)

 

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方法。

 

你可能感兴趣的:(java hibernate)