会变成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()所致。