Hibernate 批量加载(立即、延迟)

本文探讨了Hibernate中立即加载与延迟加载策略下批量加载的实现方式及优化技巧。通过设置batch-size参数,可以有效减少数据库查询次数,提升性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、批量立即加载

以上面的例子为例:

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语句去查询。反而增加了系统的开销。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值