`
sctom123
  • 浏览: 112553 次
  • 性别: 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  

相关推荐

    Hibernate源码解析(一)

    《Hibernate源码解析(一)》 在Java开发领域,Hibernate作为一款强大的对象关系映射(ORM)框架,极大地简化了数据库操作。深入理解Hibernate的源码,不仅可以帮助开发者更好地运用该工具,还能提升对Java编程和...

    Hibernate基础学习源码

    本资源“Hibernate基础学习源码”提供了五个不同阶段的学习示例,分别命名为Hibernate_01至Hibernate_04以及Hibernate_M2M,涵盖了Hibernate的基本概念、配置、实体映射、CRUD操作以及多对多关系的处理。 1. **...

    hibernate源码

    总结,Hibernate源码的学习不仅能帮助开发者理解ORM框架的设计原理,还能提升数据库操作的效率和代码的可维护性。通过对源码的深入研究,我们可以更好地利用Hibernate提供的功能,优化我们的应用,同时也能为自己的...

    精通hibernate源码ch2

    在深入探讨Hibernate源码之前,...通过深入学习Hibernate源码,我们可以更好地理解其工作原理,优化数据库操作,提高应用性能。同时,对源码的了解也有助于我们解决实际开发中遇到的问题,定制更适合项目需求的功能。

    hibernate源码release-4.1.4.Final版

    通过深入学习Hibernate 4.1.4.Final的源码,我们可以更好地理解其设计思想,提升我们的编程技巧,同时也能为日常开发中遇到的问题提供解决方案。这是一份宝贵的资源,无论是对于初学者还是经验丰富的开发者,都值得...

    hibernate入门学习笔记+源码

    **hibernate入门学习笔记+源码** **一、Hibernate简介** Hibernate是一个开源的对象关系映射(ORM)框架,它简化了Java应用与数据库之间的交互。通过提供对象化的数据访问方式,Hibernate消除了传统JDBC代码中的...

    精通hibernate源码ch3

    总的来说,“精通Hibernate源码Chapter 3”涵盖了对象持久化的基础理论和实践技巧,通过学习源码,开发者能够更深入地理解Hibernate的工作机制,提高开发和调试的效率。在实际项目中,熟练掌握Hibernate不仅能够简化...

    Hibernate3源码

    Hibernate3作为历史版本,虽然已被更先进的Hibernate4和5所取代,但其源码仍具有极高的学习价值,特别是对于理解ORM框架的工作原理、事务管理、缓存机制等方面。 一、Hibernate3概述 Hibernate3是在Hibernate2的...

    hibernate-3.2源码包

    1. **对象关系映射(ORM)**:Hibernate 提供了一种机制,将Java类映射到数据库表,使得开发者可以使用面向对象的方式来操作数据库,而无需编写大量SQL语句。 2. **配置文件(hibernate.cfg.xml)**:这是 ...

    Struts2+hibernate 源码

    它支持实体类的CRUD(Create、Read、Update、Delete)操作,自动处理SQL语句的生成和执行。Hibernate使用配置文件(hibernate.cfg.xml)和映射文件(.hbm.xml)来定义数据库连接和对象关系。此外,Hibernate还提供了...

    hibernate3基础教程中文版及源码

    《Hibernate3基础教程中文版及源码》是一个针对Java开发者的重要资源,旨在深入理解并实践Hibernate3这一流行的对象关系映射(ORM)框架。Hibernate3是Java开发中的一个关键工具,它极大地简化了数据库操作,使得...

    精通hibernate源码ch1

    《精通Hibernate源码Chapter1:Java对象持久化技术详解》 在Java开发中,Hibernate作为一款强大的对象关系映射(ORM)框架,极大地简化了数据库操作。深入理解Hibernate的源码,不仅可以帮助开发者更好地利用其功能...

    Hibernate源码下载

    通过深入学习和分析Hibernate源码,开发者不仅可以提升自身的ORM技术,还能掌握软件设计模式、数据库交互原理等多方面技能。同时,对于遇到的问题,源码调试能够帮助找到问题根源,提供解决方案。对于初学者而言,这...

    Hibernate开发租房系统2 源码

    标题为“Hibernate开发租房系统2 源码”,表明这是一个关于使用Hibernate进行实际项目开发的案例,特别关注了数据模型中的关联策略。描述提到“使用cascade和inverse优化区和街道关联关系”,这意味着我们将深入理解...

    hibernate,hibernate实例源码

    【hibernate,hibernate实例源码】 Hibernate是一个开源的对象关系映射(ORM)框架,它极大地简化了Java应用程序与数据库之间的交互。通过提供一套API和元数据配置,Hibernate可以将Java对象自动持久化到关系数据库...

    hibernate3.6.1源码

    Hibernate 是一个著名的开源Java对象关系映射(ORM)框架,它极大地简化了数据库与Java应用程序之间的交互。在本文中,我们将深入探讨Hibernate 3.6.1版本的源码,了解其内部工作原理以及关键组件的功能。 源码分析...

    hibernate5.2.7-src源码

    《深入剖析Hibernate ...通过深入学习Hibernate 5.2.7的源码,我们可以更好地理解其内部机制,从而在实际项目中更高效地利用这个强大的ORM框架。这不仅有助于提升开发效率,也有助于解决在使用过程中遇到的各种问题。

    hibernate源代码的zip文件

    《深入剖析Hibernate源码》 Hibernate,作为Java领域中的一款著名持久化框架,极大地简化了数据库操作,使得开发者能够更加专注于业务逻辑而非繁琐的数据交互。本文将基于“hibernate源代码的zip文件”展开,深入...

    hibernate入门源代码

    Hibernate 是一款开源的对象关系映射(ORM)框架,它极大地简化了Java应用程序对数据库的操作。这个资源包包含了“chapter07”目录下的源代码,是学习Hibernate基础知识的理想起点。让我们逐步解析这些源代码,了解...

Global site tag (gtag.js) - Google Analytics