hibernate的fetch=“subselect"碰上SQLQuery

会变成fetch="select"

 

List<User> users = sesson.createSQLQuery("select {u.*} from user_table u where ...")
                                          .addEntity("u", User.class).list();
for(User u : users){
  Hibernate.initialize(u.getAddresses());
  //just initialize the first entity's collection property,
  // subselect fetch mode will fetch 
  //collection property for all entities in current session.
  break;
}

 观察打印出来的sql:
1.normal sql: select ... from user_table u where ...
2.fetch sql: select ... from address_table a where a.user_id in (?,?,?,...)

fetch sql并非预想中的:select ... from address_table a where a.user_id in (select u.id from user_table u where ...)

 

关于subselect的局限性,GK语焉不详的回答在这里:
http://opensource.atlassian.com/projects/hibernate/browse/HHH-304

结论:
谨慎使用subselect fetch mode,该模式主要是为了防止batch fetch(fetch="select"并设置了相应的batch size)的碎片化,但是使用in语法,值得改进,且某些情况下自动转变成batch fetch。
尽可能使用默认的select fetch mode并合理设置batch fetch size。在主sql已经是分页查询的情况下,subselect fetch mode是没有必要的。在主sql不是分页查询的情况下,估计结果集大小,结果集非常大的情况下,考虑使用subselect fetch。

 

上面这个例子如果非得保持subselect fetch设置,那就按照batch fetch 的方式老老实实的初始化:

 

for(User u : users){
  Hibernate.initialize(u.getAddresses());
}
 



以上仅根据调试结果和hibernate手册,并未研究hibernate源码的具体实现。欢迎指正。

 

另,今天看源码发现是由于CommonLoader出于某种考虑并未覆盖父类的isSubselectLoadingEnabled()所致。

你可能感兴趣的:(sql,Hibernate,OpenSource)