hibernate 源码学习 多出来的update语句 之一
2009-11-03 09:46
267 查看
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自带的例子,
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();
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语句有三条.
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 {
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 {
//create all the new entries
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 );
//TODO: copy/paste from insertRows()
int loc = writeKey( st, id, offset, session );
if ( hasIdentifier ) {
loc = writeIdentifier( st, collection.getIdentifier(entry, i), loc, session );
}
if ( hasIndex /*&& !indexIsFormula*/ ) {
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 代码
/**
* process any unreferenced collections and then inspect all known collections,
* scheduling creates/removes/updates
*/
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 );
}
}
// Schedule updates to collections:
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 代码
/**
* Perform all currently queued actions.
*
* @throws HibernateException error executing queued actions.
*/
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 );就不会被调用了。
结论:我们总是习惯性的问为什么,其实它就是这么做的,种什么花,结什么果。
this.persister = persister;
this.session = session;
this.key = key;
this.collectionRole = persister.getRole();
this.collection = collection;
}
<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自带的例子,
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();
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语句有三条.
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 {
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 {
//create all the new entries
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 );
//TODO: copy/paste from insertRows()
int loc = writeKey( st, id, offset, session );
if ( hasIdentifier ) {
loc = writeIdentifier( st, collection.getIdentifier(entry, i), loc, session );
}
if ( hasIndex /*&& !indexIsFormula*/ ) {
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 代码
/**
* process any unreferenced collections and then inspect all known collections,
* scheduling creates/removes/updates
*/
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 );
}
}
// Schedule updates to collections:
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 代码
/**
* Perform all currently queued actions.
*
* @throws HibernateException error executing queued actions.
*/
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 );就不会被调用了。
结论:我们总是习惯性的问为什么,其实它就是这么做的,种什么花,结什么果。
this.persister = persister;
this.session = session;
this.key = key;
this.collectionRole = persister.getRole();
this.collection = collection;
}
相关文章推荐
- hibernate“update”语句执行成功数据库却没有更新成功
- Hibernate学习笔记 merge()方法--update 之补充
- hibernate利用@DynamicInsert和@DynamicUpdate生成动态SQL语句
- 关于spring整合hibernate使用update无异常但没有效果(不输出sql语句)
- Hibernate的HQL查询语句对比Sql语句学习
- 关于spring整合hibernate使用update无异常但没有效果(不输出sql语句)
- 学习笔记—— 一些UPDATE语句
- Hibernate执行update操作之后查询跟新的语句出错
- 几个比较好的java学习网站(Struts,Servlet,jar源码,hibernate,java基础知识)
- [Go语言]从Docker源码学习Go——if语句和map结构
- Jimoshi_Hibernate 框架学习(四)--事务隔离级别、Hibernate执行SQL、HQL语句、连接池、Hibernate二级缓存
- SSH学习(十)Hibernate常用API详解及源码分析
- java优化Hibernate利用@DynamicInsert和@DynamicUpdate生成动态SQL语句
- 【SQL Server学习笔记】INSERT、UPDATE 语句
- mybatis源码学习之执行过程分析(4)——映射文件中sql的获取和sql语句的执行
- [原创]java WEB学习笔记90:Hibernate学习之路-- -HQL检索方式,分页查询,命名查询语句,投影查询,报表查询
- Hibernate 有选择性的更新--控制insert和update语句
- Hibernate利用@DynamicInsert和@DynamicUpdate生成动态SQL语句
- 【转】Hibernate利用@DynamicInsert和@DynamicUpdate生成动态SQL语句
- 学习笔记—— 一些UPDATE语句