一、批量立即加载
以上面的例子为例:
Team对学生采取的是立即加载
客户端:
Session session = SessionUtil.getSession();
Transaction tran = session.beginTransaction();
Query query = session.createQuery("from Team");
List list = query.list();
tran.commit();
session.close();
数据库中有5个TEAM,对应每个TEAM都有学生,那么打印语句:
Hibernate: select team0_.ID as ID0_, team0_.Name as Name0_ from test.team team0_
Hibernate: select students0_.teamID as teamID3_, students0_.ID as ID3_, students0_.ID as ID1_2_, students0_.Name as Name1_2_, students0_.TeamID as TeamID1_2_, team1_.ID as ID0_0_, team1_.Name as Name0_0_, card2_.ID as ID2_1_, card2_.StudentID as StudentID2_1_, card2_.Name as Name2_1_ from test.student students0_ left outer join test.team team1_ on students0_.TeamID=team1_.ID left outer join test.card card2_ on students0_.ID=card2_.ID where students0_.teamID=?
Hibernate: select students0_.teamID as teamID3_, students0_.ID as ID3_, students0_.ID as ID1_2_, students0_.Name as Name1_2_, students0_.TeamID as TeamID1_2_, team1_.ID as ID0_0_, team1_.Name as Name0_0_, card2_.ID as ID2_1_, card2_.StudentID as StudentID2_1_, card2_.Name as Name2_1_ from test.student students0_ left outer join test.team team1_ on students0_.TeamID=team1_.ID left outer join test.card card2_ on students0_.ID=card2_.ID where students0_.teamID=?
Hibernate: select students0_.teamID as teamID3_, students0_.ID as ID3_, students0_.ID as ID1_2_, students0_.Name as Name1_2_, students0_.TeamID as TeamID1_2_, team1_.ID as ID0_0_, team1_.Name as Name0_0_, card2_.ID as ID2_1_, card2_.StudentID as StudentID2_1_, card2_.Name as Name2_1_ from test.student students0_ left outer join test.team team1_ on students0_.TeamID=team1_.ID left outer join test.card card2_ on students0_.ID=card2_.ID where students0_.teamID=?
Hibernate: select students0_.teamID as teamID3_, students0_.ID as ID3_, students0_.ID as ID1_2_, students0_.Name as Name1_2_, students0_.TeamID as TeamID1_2_, team1_.ID as ID0_0_, team1_.Name as Name0_0_, card2_.ID as ID2_1_, card2_.StudentID as StudentID2_1_, card2_.Name as Name2_1_ from test.student students0_ left outer join test.team team1_ on students0_.TeamID=team1_.ID left outer join test.card card2_ on students0_.ID=card2_.ID where students0_.teamID=?
Hibernate: select students0_.teamID as teamID3_, students0_.ID as ID3_, students0_.ID as ID1_2_, students0_.Name as Name1_2_, students0_.TeamID as TeamID1_2_, team1_.ID as ID0_0_, team1_.Name as Name0_0_, card2_.ID as ID2_1_, card2_.StudentID as StudentID2_1_, card2_.Name as Name2_1_ from test.student students0_ left outer join test.team team1_ on students0_.TeamID=team1_.ID left outer join test.card card2_ on students0_.ID=card2_.ID where students0_.teamID=?
对于以上语句,首先查询TEAM的值,因为采取的是立即加载,对有多少个班级就发出多少条SQL语句。如果有100个班级,那么就会发出100条的查询语句,性能可以想象!!所以一定要改变这种情况。
我们可以在一对多的一的这端的:
<set name="students" inverse="true" cascade="all" lazy="false" batch-size="2">
<key column="teamID"></key>
<one-to-many class="com.vo.Student"></one-to-many>
</set>
设置batch-size的值,首先来看看采用这种策略以后的语句:
Hibernate: select team0_.ID as ID0_, team0_.Name as Name0_ from test.team team0_
Hibernate: select students0_.teamID as teamID3_, students0_.ID as ID3_, students0_.ID as ID1_2_, students0_.Name as Name1_2_, students0_.TeamID as TeamID1_2_, team1_.ID as ID0_0_, team1_.Name as Name0_0_, card2_.ID as ID2_1_, card2_.StudentID as StudentID2_1_, card2_.Name as Name2_1_ from test.student students0_ left outer join test.team team1_ on students0_.TeamID=team1_.ID left outer join test.card card2_ on students0_.ID=card2_.ID where students0_.teamID in (?, ?)
Hibernate: select students0_.teamID as teamID3_, students0_.ID as ID3_, students0_.ID as ID1_2_, students0_.Name as Name1_2_, students0_.TeamID as TeamID1_2_, team1_.ID as ID0_0_, team1_.Name as Name0_0_, card2_.ID as ID2_1_, card2_.StudentID as StudentID2_1_, card2_.Name as Name2_1_ from test.student students0_ left outer join test.team team1_ on students0_.TeamID=team1_.ID left outer join test.card card2_ on students0_.ID=card2_.ID where students0_.teamID in (?, ?)
Hibernate: select students0_.teamID as teamID3_, students0_.ID as ID3_, students0_.ID as ID1_2_, students0_.Name as Name1_2_, students0_.TeamID as TeamID1_2_, team1_.ID as ID0_0_, team1_.Name as Name0_0_, card2_.ID as ID2_1_, card2_.StudentID as StudentID2_1_, card2_.Name as Name2_1_ from test.student students0_ left outer join test.team team1_ on students0_.TeamID=team1_.ID left outer join test.card card2_ on students0_.ID=card2_.ID where students0_.teamID=?
发现采取的查询策略改变了,SQL的条件是where id in(?,?)
因为设置了批量加载为2,假如有100个班级,那么只要加载50次,如果设置为3,那么就是加载100/3=33次,剩余的一次采用立即加载的方式,所以这也是为什么上面例子的最后一句是立即加载的原因。
没有用batch_size的SQL采用ID=?的形式
采用batch_size的SQL采用ID in()的形式。
这就是为什么SQL语句会减少的原因。
二、批量延迟加载
首先在TEAM的配置文件中更改对学生的加载策略为延迟加载。并且设置批量加载为2.
客户端:
Session session = SessionUtil.getSession();
Transaction tran = session.beginTransaction();
Query query = session.createQuery("from Team");
List list = query.list();
Team team = (Team)list.get(0);
System.out.println(team.getName()+" 学生数量:"+team.getStudents().size());
team = (Team)list.get(2);
System.out.println(team.getName()+" 学生数量:"+team.getStudents().size());
team = (Team)list.get(4);
System.out.println(team.getName()+" 学生数量:"+team.getStudents().size());
tran.commit();
session.close();
打印语句:
Hibernate: select team0_.ID as ID0_, team0_.Name as Name0_ from test.team team0_
Hibernate: select students0_.teamID as teamID3_, students0_.ID as ID3_, students0_.ID as ID1_2_, students0_.Name as Name1_2_, students0_.TeamID as TeamID1_2_, team1_.ID as ID0_0_, team1_.Name as Name0_0_, card2_.ID as ID2_1_, card2_.StudentID as StudentID2_1_, card2_.Name as Name2_1_ from test.student students0_ left outer join test.team team1_ on students0_.TeamID=team1_.ID left outer join test.card card2_ on students0_.ID=card2_.ID where students0_.teamID in (?, ?)
二中 学生数量:2
一职 学生数量:1
Hibernate: select students0_.teamID as teamID3_, students0_.ID as ID3_, students0_.ID as ID1_2_, students0_.Name as Name1_2_, students0_.TeamID as TeamID1_2_, team1_.ID as ID0_0_, team1_.Name as Name0_0_, card2_.ID as ID2_1_, card2_.StudentID as StudentID2_1_, card2_.Name as Name2_1_ from test.student students0_ left outer join test.team team1_ on students0_.TeamID=team1_.ID left outer join test.card card2_ on students0_.ID=card2_.ID where students0_.teamID in (?, ?)
十一中 学生数量:1
第1条的解释:首先去查询TEAM的集合对象。
第2条的解释:因为采用的是延迟加载,只有当用到对象的属性的时候才发送SQL去数据库取值,所以发出第2条语句,因为设置了批量加载为2,所以发出的该条SQL语句将把班级序号为1和2的班级都查出来,所以当我们去取得班级为2的时候就不再发送查询语句了。
第3条SQL解释:因为打印的是第4个班级,所以要再发送一条查询语句。
对于批量加载也不是设置的batch_size越大越好。
例如,对于A-B(有5个B对象),我们设置的batch_size=5,当我们只要查询中间的一条数据,系统会发出5条SQL语句去查询。反而增加了系统的开销。