Hibernate之综合问题

本文深入探讨了Hibernate中的N+1问题及其解决方案,重点介绍了如何利用Session级缓存机制避免N+1问题的出现。通过实例演示了使用list和iterate方法的不同效果,并解释了它们在缓存管理、内存溢出预防等方面的区别。

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

n + 1问题

query.iterate()方式返回迭代查询会开始发出一条语句:查询所有记录ID语句

     Hibernate: select student0_.id ascol_0_0_from t_student student0_

然后有多少条记录,会发出多少条查询语句。

n + 1问题:n:有n条记录,发出n条查询语句;1 :发出一条查询所有记录ID语句。

出现n+1的原因:因为iterate(迭代查询)是使用缓存的,第一次查询数据时发出查询语句加载数据并加入到缓存,以后再查询时hibernate会先到ession缓存(一级缓存)中查看数据是否存在,如果存在则直接取出使用,否则发出查询语句进行查询。

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. session=HibernateUtils.getSession();  
  2. tx = session.beginTransaction();  
  3.   
  4. /** 
  5.  * 出现N+1问题 
  6.  * 发出查询id列表的sql语句 
  7.  * Hibernate: select student0_.idas col_0_0_ from t_student student0_ 
  8.  * 
  9.  * 再依次发出根据id查询Student对象的sql语句 
  10.  * Hibernate: select student0_.idas id1_0_, student0_.name as name1_0_, 
  11.  * student0_.createTime ascreateTime1_0_, student0_.classesid as classesid1_0_ 
  12.  * from t_student student0_ wherestudent0_.id=? 
  13.  */  
  14. Iterator students =session.createQuery("fromStudent").iterate();  
  15.   
  16. while (students.hasNext()){  
  17.    Student student=(Student)students.next();  
  18.    System.out.println(student.getName());  
  19. }  
  20. tx.commit();  


先执行query.list(),再执行query.iterate,这样不会出现N+1问题

因为list操作已经将Student对象放到了一级缓存中,所以再次使用iterate操作的时候

它首先发出一条查询id列表的sql,再根据id到缓存中取数据,只有在缓存中找不到相应的

数据时,才会发出sql到数据库中查询

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. List students =session.createQuery("from Student").list();  
  2.   
  3. for (Iterator iter =students.iterator();iter.hasNext();){  
  4.     Student student=(Student)iter.next();  
  5.    System.out.println(student.getName());  
  6. }                      System.out.println("---------------------------------------------------------");  
  7.  // 不会出现N+1问题,因为list操作已经将数据加入到一级缓存。  
  8. Iterator iters=session.createQuery("from Student").iterate();  
  9.   
  10. while (iters.hasNext()){  
  11.     Student student=(Student)iters.next();  
  12.    System.out.println(student.getName());  
  13. }  


list 和 iterate不同之处

a) list取所有

b) Iterate先取ID,等用到的时候再根据ID来取对象

c) session中list第二次发出,仍会到数据库查询

d) iterate第二次,首先找session级缓存

 

Session级缓存(一级缓存)

一级缓存很短和session的生命周期一致,因此也叫session级缓存或事务级缓存

       

哪些方法支持一级缓存:

         get()

         load()

         iterate(查询实体对象)

如何管理一级缓存:

         session.clear(),session.evict()

如何避免一次性大量的实体数据入库导致内存溢出

         先flush,再clear

       

如果数据量特别大,考虑采用jdbc实现,如果jdbc也不能满足要求可以考虑采用数据本身的特定导入工具

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值