`
sctom123
  • 浏览: 110049 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

hibernate 源码学习 多出来的update语句 之一

阅读更多
xml 代码
  1. <class name="A" entity-name="A" table="aaa">           
  2.     <id name="id">  
  3.         <generator class="native"/>  
  4.     id>   部分,它加了一个CollectionRecreateAction。这就为update 语句埋下了伏笔。
  5.     <array name="bs" cascade="all" fetch="join"  >  
  6.         <key column="a_id"/>  
  7.         <list-index column="idx"/>  
  8.         <one-to-many class="B"/>  
  9.     array>  
  10. class>  
  11. <class name="B" lazy="true" table="bbb">  
  12.     <id name="id">  
  13.         <generator class="native"/>  
  14.     id>  
  15. class>  
这是一个hibernate自带的例子,
java 代码
  1. Session s;   
  2. Transaction tx;   
  3. s = openSession();   
  4. tx = s.beginTransaction();   
  5. A a = new A();   
  6. B b = new B();   
  7. a.setBs( new B[] {b} );   
  8. s.persist("A",a);   
  9. tx.commit();   
  10. s.close();    

会发现生成的sql语句有三条.

sql 代码
  1. insert       into  
  2.     aaa   
  3.     (id)    
  4. values  
  5.     (?)   
  6. insert    
  7. into  
  8.     bbb   
  9.     (id)    
  10. values  
  11.     (?)   
  12. update  
  13.     bbb    
  14. set  
  15.     a_id=?,   
  16.     idx=?    
  17. where  
  18.     id=?  

当然一般来说,你应该配置双向关联,在A的这一方设置reverse为true。但是很多人会有这样的疑问,我的顺序不就是先插入A,再插入B,当我不设置reverse的时候,究竟发生了什么,不禁想到hibernate源码中探个究竟。

通过调试,发现在flush的时候,先执行两条insert语句,然后产生一条update语句,并在下面的方法里面,初始化CollectionAction对象,这个对象会被 AbstractCollectionPersister 的recreate方法调用,为update的那一个 preparement 赋参数。(sql server) ,在oracle的环境下,由于在flush之前的persist动作的时候,就会调    select
        hibernate_sequence.nextval
    from
        dual

取出主键,所以初始化CollectionAction对象这个方法,发生在insert sql 语句之前

java 代码
  1. public CollectionAction(   
  2.         final CollectionPersister persister,    
  3.         final PersistentCollection collection,    
  4.         final Serializable key,    
  5.         final SessionImplementor session)   
  6. throws CacheException {   
  7.     this.persister = persister;   
  8.     this.session = session;   
  9.     this.key = key;   
  10.     this.collectionRole = persister.getRole();   
  11.     this.collection = collection;   
  12. }  
java 代码
  1. public void recreate(PersistentCollection collection, Serializable id, SessionImplementor session)   
  2.         throws HibernateException {   
  3.   
  4.     if ( !isInverse && isRowInsertEnabled() ) {   
  5.   
  6.         if ( log.isDebugEnabled() ) {   
  7.             log.debug(    
  8.                     "Inserting collection: " +    
  9.                     MessageHelper.collectionInfoString( this, id, getFactory() )    
  10.                 );   
  11.         }   
  12.   
  13.         try {   
  14.             //create all the new entries   
  15.             Iterator entries = collection.entries(this);   
  16.             if ( entries.hasNext() ) {   
  17.                 collection.preInsert( this );   
  18.                 int i = 0;   
  19.                 int count = 0;   
  20.                 while ( entries.hasNext() ) {   
  21.   
  22.                     final Object entry = entries.next();   
  23.                     if ( collection.entryExists( entry, i ) ) {   
  24.                         int offset = 1;   
  25.                         PreparedStatement st = null;   
  26.                         Expectation expectation = Expectations.appropriateExpectation( getInsertCheckStyle() );   
  27.                         boolean callable = isInsertCallable();   
  28.                         boolean useBatch = expectation.canBeBatched();   
  29.                         String sql = getSQLInsertRowString();   
  30.   
  31.                         if ( useBatch ) {   
  32.                             if ( callable ) {   
  33.                                 st = session.getBatcher().prepareBatchCallableStatement( sql );   
  34.                             }   
  35.                             else {   
  36.                                 st = session.getBatcher().prepareBatchStatement( sql );   
  37.                             }   
  38.                         }   
  39.                         else {   
  40.                             if ( callable ) {   
  41.                                 st = session.getBatcher().prepareCallableStatement( sql );   
  42.                             }   
  43.                             else {   
  44.                                 st = session.getBatcher().prepareStatement( sql );   
  45.                             }   
  46.                         }   
  47.   
  48.   
  49.                         try {   
  50.                             offset+= expectation.prepare( st );   
  51.   
  52.                             //TODO: copy/paste from insertRows()   
  53.                             int loc = writeKey( st, id, offset, session );   
  54.                             if ( hasIdentifier ) {   
  55.                                 loc = writeIdentifier( st, collection.getIdentifier(entry, i), loc, session );   
  56.                             }   
  57.                             if ( hasIndex /*&& !indexIsFormula*/ ) {   
  58.                                 loc = writeIndex( st, collection.getIndex(entry, i, this), loc, session );   
  59.                             }   
  60.                             loc = writeElement(st, collection.getElement(entry), loc, session );   
  61.   
  62.                             if ( useBatch ) {   
  63.                                 session.getBatcher().addToBatch( expectation );   
  64.                             }   
  65.                             else {   
  66.                                 expectation.verifyOutcome( st.executeUpdate(), st, -1 );   
  67.                             }   
  68.   
  69.                             collection.afterRowInsert( this, entry, i );   
  70.                             count++;   
  71.                         }   
  72.                         catch ( SQLException sqle ) {   
  73.                             if ( useBatch ) {   
  74.                                 session.getBatcher().abortBatch( sqle );   
  75.                             }   
  76.                             throw sqle;   
  77.                         }   
  78.                         finally {   
  79.                             if ( !useBatch ) {   
  80.                                 session.getBatcher().closeStatement( st );   
  81.                             }   
  82.                         }   
  83.   
  84.                     }   
  85.                     i++;   
  86.                 }   
  87.   
  88.                 if ( log.isDebugEnabled() ) {   
  89.                     log.debug( "done inserting collection: " + count + " rows inserted" );   
  90.                 }   
  91.   
  92.             }   
  93.             else {   
  94.                 if ( log.isDebugEnabled() ) {   
  95.                     log.debug( "collection was empty" );   
  96.                 }   
  97.             }   
  98.         }   
  99.         catch ( SQLException sqle ) {   
  100.             throw JDBCExceptionHelper.convert(   
  101.                     sqlExceptionConverter,   
  102.                     sqle,   
  103.                     "could not insert collection: " +    
  104.                     MessageHelper.collectionInfoString( this, id, getFactory() ),   
  105.                     getSQLInsertRowString()   
  106.                 );   
  107.         }   
  108.     }   
  109. }  

 

以上是AbstractCollectionPersister类的一个方法。     那么这里我知道了是什么时候在为update prepament 赋值,但是我还是不知道为什么要分成三个sql语句执行。首先我们来看 update 语句产生的来龙去脉。

java 代码
  1. /**  
  2.  * process any unreferenced collections and then inspect all known collections,  
  3.  * scheduling creates/removes/updates  
  4.  */  
  5. private void flushCollections(EventSource session) throws HibernateException {   
  6.   
  7.     log.trace("Processing unreferenced collections");   
  8.   
  9.     List list = IdentityMap.entries( session.getPersistenceContext().getCollectionEntries() );   
  10.     int size = list.size();   
  11.     for ( int i = 0; i < size; i++ ) {   
  12.         Map.Entry me = ( Map.Entry ) list.get( i );   
  13.         CollectionEntry ce = (CollectionEntry) me.getValue();   
  14.         if ( !ce.isReached() && !ce.isIgnore() ) {   
  15.             Collections.processUnreachableCollection( (PersistentCollection) me.getKey(), session );   
  16.         }   
  17.     }   
  18.   
  19.     // Schedule updates to collections:   
  20.   
  21.     log.trace( "Scheduling collection removes/(re)creates/updates" );   
  22.   
  23.     list = IdentityMap.entries( session.getPersistenceContext().getCollectionEntries() );   
  24.     size = list.size();   
  25.     ActionQueue actionQueue = session.getActionQueue();   
  26.     for ( int i = 0; i < size; i++ ) {   
  27.         Map.Entry me = (Map.Entry) list.get(i);   
  28.         PersistentCollection coll = (PersistentCollection) me.getKey();   
  29.         CollectionEntry ce = (CollectionEntry) me.getValue();   
  30.   
  31.         if ( ce.isDorecreate() ) {   
  32.             session.getInterceptor().onCollectionRecreate( coll, ce.getCurrentKey() );   
  33.             actionQueue.addAction(   
  34.                     new CollectionRecreateAction(    
  35.                             coll,    
  36.                             ce.getCurrentPersister(),    
  37.                             ce.getCurrentKey(),    
  38.                             session    
  39.                         )   
  40.                 );   
  41.         }   
  42.         if ( ce.isDoremove() ) {   
  43.             session.getInterceptor().onCollectionRemove( coll, ce.getLoadedKey() );   
  44.             actionQueue.addAction(   
  45.                     new CollectionRemoveAction(    
  46.                             coll,    
  47.                             ce.getLoadedPersister(),    
  48.                             ce.getLoadedKey(),    
  49.                             ce.isSnapshotEmpty(coll),    
  50.                             session    
  51.                         )   
  52.                 );   
  53.         }   
  54.         if ( ce.isDoupdate() ) {   
  55.             session.getInterceptor().onCollectionUpdate( coll, ce.getLoadedKey() );   
  56.             actionQueue.addAction(   
  57.                     new CollectionUpdateAction(    
  58.                             coll,    
  59.                             ce.getLoadedPersister(),    
  60.                             ce.getLoadedKey(),    
  61.                             ce.isSnapshotEmpty(coll),    
  62.                             session    
  63.                         )   
  64.                 );   
  65.         }   
  66.   
  67.     }   
  68.   
  69.     actionQueue.sortCollectionActions();   
  70.        
  71. }  

 

在flush的时候,会调用上面的方法,注意

java 代码
  1. actionQueue.addAction(   
  2.         new CollectionRecreateAction(    
  3.                 coll,    
  4.                 ce.getCurrentPersister(),    
  5.                 ce.getCurrentKey(),    
  6.                 session    
  7.             )   
  8.     );  

 

如果你把AbstractFlushingEventListener 的日志设成debug,可以看到如下日志:

11:56:10,257 DEBUG AbstractFlushingEventListener:85 - Flushed: 2 insertions, 0 updates, 0 deletions to 2 objects
11:57:11,445 DEBUG AbstractFlushingEventListener:91 - Flushed: 1 (re)creations, 0 updates, 0 removals to 1 collections
11:57:16,753 DEBUG Printer:83 - listing entities:
11:57:16,753 DEBUG Printer:90 - org.hibernate.test.array.B{id=2}
11:57:16,753 DEBUG Printer:90 - org.hibernate.test.array.A

着色的部分,显示将会有一个1 (re)creations,实际上这就是那条update语句。

而在ActionQueue

java 代码
  1. /**  
  2.  * Perform all currently queued actions.  
  3.  *  
  4.  * @throws HibernateException error executing queued actions.  
  5.  */  
  6. public void executeActions() throws HibernateException {   
  7.     executeActions( insertions );   
  8.     executeActions( updates );   
  9.     executeActions( collectionRemovals );   
  10.     executeActions( collectionUpdates );   
  11.     executeActions( collectionCreations );   
  12.     executeActions( deletions );   
  13. }  

 

当executeActions( collectionCreations );这一句被调用时,就产生了哪一条update sql语句被调用。

其实到这里我就大致明白了。A作为主动方,它的处理方式就是产生一个update语句,得再对比一下inverse=true的情况。

而inverse=true的时候,executeActions( collectionCreations );就不会被调用了。

结论:我们总是习惯性的问为什么,其实它就是这么做的,种什么花,结什么果。

 

分享到:
评论
1 楼 qxk0210 2007-06-05  

相关推荐

Global site tag (gtag.js) - Google Analytics