xml 代码
- <class name="A" entity-name="A" table="aaa">
- <id name="id">
- <generator class="native"/>
- id> 部分,它加了一个CollectionRecreateAction。这就为update 语句埋下了伏笔。
- <array name="bs" cascade="all" fetch="join" >
- <key column="a_id"/>
- <list-index column="idx"/>
- <one-to-many class="B"/>
- array>
- class>
- <class name="B" lazy="true" table="bbb">
- <id name="id">
- <generator class="native"/>
- id>
- class>
这是一个hibernate自带的例子,
java 代码
- Session s;
- Transaction tx;
- s = openSession();
- tx = s.beginTransaction();
- A a = new A();
- B b = new B();
- a.setBs( new B[] {b} );
- s.persist("A",a);
- tx.commit();
- s.close();
会发现生成的sql语句有三条.
sql 代码
- insert into
- aaa
- (id)
- values
- (?)
- insert
- into
- bbb
- (id)
- values
- (?)
- update
- bbb
- set
- a_id=?,
- idx=?
- where
- 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 代码
- public CollectionAction(
- final CollectionPersister persister,
- final PersistentCollection collection,
- final Serializable key,
- final SessionImplementor session)
- throws CacheException {
- this.persister = persister;
- this.session = session;
- this.key = key;
- this.collectionRole = persister.getRole();
- this.collection = collection;
- }
java 代码
- public void recreate(PersistentCollection collection, Serializable id, SessionImplementor session)
- throws HibernateException {
-
- if ( !isInverse && isRowInsertEnabled() ) {
-
- if ( log.isDebugEnabled() ) {
- log.debug(
- "Inserting collection: " +
- MessageHelper.collectionInfoString( this, id, getFactory() )
- );
- }
-
- try {
-
- Iterator entries = collection.entries(this);
- if ( entries.hasNext() ) {
- collection.preInsert( this );
- int i = 0;
- int count = 0;
- while ( entries.hasNext() ) {
-
- final Object entry = entries.next();
- if ( collection.entryExists( entry, i ) ) {
- int offset = 1;
- PreparedStatement st = null;
- Expectation expectation = Expectations.appropriateExpectation( getInsertCheckStyle() );
- boolean callable = isInsertCallable();
- boolean useBatch = expectation.canBeBatched();
- String sql = getSQLInsertRowString();
-
- if ( useBatch ) {
- if ( callable ) {
- st = session.getBatcher().prepareBatchCallableStatement( sql );
- }
- else {
- st = session.getBatcher().prepareBatchStatement( sql );
- }
- }
- else {
- if ( callable ) {
- st = session.getBatcher().prepareCallableStatement( sql );
- }
- else {
- st = session.getBatcher().prepareStatement( sql );
- }
- }
-
-
- try {
- offset+= expectation.prepare( st );
-
-
- int loc = writeKey( st, id, offset, session );
- if ( hasIdentifier ) {
- loc = writeIdentifier( st, collection.getIdentifier(entry, i), loc, session );
- }
- if ( hasIndex ) {
- loc = writeIndex( st, collection.getIndex(entry, i, this), loc, session );
- }
- loc = writeElement(st, collection.getElement(entry), loc, session );
-
- if ( useBatch ) {
- session.getBatcher().addToBatch( expectation );
- }
- else {
- expectation.verifyOutcome( st.executeUpdate(), st, -1 );
- }
-
- collection.afterRowInsert( this, entry, i );
- count++;
- }
- catch ( SQLException sqle ) {
- if ( useBatch ) {
- session.getBatcher().abortBatch( sqle );
- }
- throw sqle;
- }
- finally {
- if ( !useBatch ) {
- session.getBatcher().closeStatement( st );
- }
- }
-
- }
- i++;
- }
-
- if ( log.isDebugEnabled() ) {
- log.debug( "done inserting collection: " + count + " rows inserted" );
- }
-
- }
- else {
- if ( log.isDebugEnabled() ) {
- log.debug( "collection was empty" );
- }
- }
- }
- catch ( SQLException sqle ) {
- throw JDBCExceptionHelper.convert(
- sqlExceptionConverter,
- sqle,
- "could not insert collection: " +
- MessageHelper.collectionInfoString( this, id, getFactory() ),
- getSQLInsertRowString()
- );
- }
- }
- }
以上是AbstractCollectionPersister类的一个方法。 那么这里我知道了是什么时候在为update prepament 赋值,但是我还是不知道为什么要分成三个sql语句执行。首先我们来看 update 语句产生的来龙去脉。
java 代码
-
-
-
-
- private void flushCollections(EventSource session) throws HibernateException {
-
- log.trace("Processing unreferenced collections");
-
- List list = IdentityMap.entries( session.getPersistenceContext().getCollectionEntries() );
- int size = list.size();
- for ( int i = 0; i < size; i++ ) {
- Map.Entry me = ( Map.Entry ) list.get( i );
- CollectionEntry ce = (CollectionEntry) me.getValue();
- if ( !ce.isReached() && !ce.isIgnore() ) {
- Collections.processUnreachableCollection( (PersistentCollection) me.getKey(), session );
- }
- }
-
-
-
- log.trace( "Scheduling collection removes/(re)creates/updates" );
-
- list = IdentityMap.entries( session.getPersistenceContext().getCollectionEntries() );
- size = list.size();
- ActionQueue actionQueue = session.getActionQueue();
- for ( int i = 0; i < size; i++ ) {
- Map.Entry me = (Map.Entry) list.get(i);
- PersistentCollection coll = (PersistentCollection) me.getKey();
- CollectionEntry ce = (CollectionEntry) me.getValue();
-
- if ( ce.isDorecreate() ) {
- session.getInterceptor().onCollectionRecreate( coll, ce.getCurrentKey() );
- actionQueue.addAction(
- new CollectionRecreateAction(
- coll,
- ce.getCurrentPersister(),
- ce.getCurrentKey(),
- session
- )
- );
- }
- if ( ce.isDoremove() ) {
- session.getInterceptor().onCollectionRemove( coll, ce.getLoadedKey() );
- actionQueue.addAction(
- new CollectionRemoveAction(
- coll,
- ce.getLoadedPersister(),
- ce.getLoadedKey(),
- ce.isSnapshotEmpty(coll),
- session
- )
- );
- }
- if ( ce.isDoupdate() ) {
- session.getInterceptor().onCollectionUpdate( coll, ce.getLoadedKey() );
- actionQueue.addAction(
- new CollectionUpdateAction(
- coll,
- ce.getLoadedPersister(),
- ce.getLoadedKey(),
- ce.isSnapshotEmpty(coll),
- session
- )
- );
- }
-
- }
-
- actionQueue.sortCollectionActions();
-
- }
在flush的时候,会调用上面的方法,注意
java 代码
- actionQueue.addAction(
- new CollectionRecreateAction(
- coll,
- ce.getCurrentPersister(),
- ce.getCurrentKey(),
- session
- )
- );
如果你把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 代码
-
-
-
-
-
- public void executeActions() throws HibernateException {
- executeActions( insertions );
- executeActions( updates );
- executeActions( collectionRemovals );
- executeActions( collectionUpdates );
- executeActions( collectionCreations );
- executeActions( deletions );
- }
当executeActions( collectionCreations );这一句被调用时,就产生了哪一条update sql语句被调用。
其实到这里我就大致明白了。A作为主动方,它的处理方式就是产生一个update语句,得再对比一下inverse=true的情况。
而inverse=true的时候,executeActions( collectionCreations );就不会被调用了。
结论:我们总是习惯性的问为什么,其实它就是这么做的,种什么花,结什么果。
分享到:
相关推荐
《Hibernate源码解析(一)》 在Java开发领域,Hibernate作为一款强大的对象关系映射(ORM)框架,极大地简化了数据库操作。深入理解Hibernate的源码,不仅可以帮助开发者更好地运用该工具,还能提升对Java编程和...
本资源“Hibernate基础学习源码”提供了五个不同阶段的学习示例,分别命名为Hibernate_01至Hibernate_04以及Hibernate_M2M,涵盖了Hibernate的基本概念、配置、实体映射、CRUD操作以及多对多关系的处理。 1. **...
总结,Hibernate源码的学习不仅能帮助开发者理解ORM框架的设计原理,还能提升数据库操作的效率和代码的可维护性。通过对源码的深入研究,我们可以更好地利用Hibernate提供的功能,优化我们的应用,同时也能为自己的...
在深入探讨Hibernate源码之前,...通过深入学习Hibernate源码,我们可以更好地理解其工作原理,优化数据库操作,提高应用性能。同时,对源码的了解也有助于我们解决实际开发中遇到的问题,定制更适合项目需求的功能。
通过深入学习Hibernate 4.1.4.Final的源码,我们可以更好地理解其设计思想,提升我们的编程技巧,同时也能为日常开发中遇到的问题提供解决方案。这是一份宝贵的资源,无论是对于初学者还是经验丰富的开发者,都值得...
**hibernate入门学习笔记+源码** **一、Hibernate简介** Hibernate是一个开源的对象关系映射(ORM)框架,它简化了Java应用与数据库之间的交互。通过提供对象化的数据访问方式,Hibernate消除了传统JDBC代码中的...
总的来说,“精通Hibernate源码Chapter 3”涵盖了对象持久化的基础理论和实践技巧,通过学习源码,开发者能够更深入地理解Hibernate的工作机制,提高开发和调试的效率。在实际项目中,熟练掌握Hibernate不仅能够简化...
Hibernate3作为历史版本,虽然已被更先进的Hibernate4和5所取代,但其源码仍具有极高的学习价值,特别是对于理解ORM框架的工作原理、事务管理、缓存机制等方面。 一、Hibernate3概述 Hibernate3是在Hibernate2的...
1. **对象关系映射(ORM)**:Hibernate 提供了一种机制,将Java类映射到数据库表,使得开发者可以使用面向对象的方式来操作数据库,而无需编写大量SQL语句。 2. **配置文件(hibernate.cfg.xml)**:这是 ...
它支持实体类的CRUD(Create、Read、Update、Delete)操作,自动处理SQL语句的生成和执行。Hibernate使用配置文件(hibernate.cfg.xml)和映射文件(.hbm.xml)来定义数据库连接和对象关系。此外,Hibernate还提供了...
《Hibernate3基础教程中文版及源码》是一个针对Java开发者的重要资源,旨在深入理解并实践Hibernate3这一流行的对象关系映射(ORM)框架。Hibernate3是Java开发中的一个关键工具,它极大地简化了数据库操作,使得...
《精通Hibernate源码Chapter1:Java对象持久化技术详解》 在Java开发中,Hibernate作为一款强大的对象关系映射(ORM)框架,极大地简化了数据库操作。深入理解Hibernate的源码,不仅可以帮助开发者更好地利用其功能...
通过深入学习和分析Hibernate源码,开发者不仅可以提升自身的ORM技术,还能掌握软件设计模式、数据库交互原理等多方面技能。同时,对于遇到的问题,源码调试能够帮助找到问题根源,提供解决方案。对于初学者而言,这...
标题为“Hibernate开发租房系统2 源码”,表明这是一个关于使用Hibernate进行实际项目开发的案例,特别关注了数据模型中的关联策略。描述提到“使用cascade和inverse优化区和街道关联关系”,这意味着我们将深入理解...
【hibernate,hibernate实例源码】 Hibernate是一个开源的对象关系映射(ORM)框架,它极大地简化了Java应用程序与数据库之间的交互。通过提供一套API和元数据配置,Hibernate可以将Java对象自动持久化到关系数据库...
Hibernate 是一个著名的开源Java对象关系映射(ORM)框架,它极大地简化了数据库与Java应用程序之间的交互。在本文中,我们将深入探讨Hibernate 3.6.1版本的源码,了解其内部工作原理以及关键组件的功能。 源码分析...
《深入剖析Hibernate ...通过深入学习Hibernate 5.2.7的源码,我们可以更好地理解其内部机制,从而在实际项目中更高效地利用这个强大的ORM框架。这不仅有助于提升开发效率,也有助于解决在使用过程中遇到的各种问题。
《深入剖析Hibernate源码》 Hibernate,作为Java领域中的一款著名持久化框架,极大地简化了数据库操作,使得开发者能够更加专注于业务逻辑而非繁琐的数据交互。本文将基于“hibernate源代码的zip文件”展开,深入...
Hibernate 是一款开源的对象关系映射(ORM)框架,它极大地简化了Java应用程序对数据库的操作。这个资源包包含了“chapter07”目录下的源代码,是学习Hibernate基础知识的理想起点。让我们逐步解析这些源代码,了解...