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缓存(一级缓存)中查看数据是否存在。假设存在则直接取出使用,否则发出查询语句进行查询。
session=HibernateUtils.getSession(); tx = session.beginTransaction(); /** * 出现N+1问题 * 发出查询id列表的sql语句 * Hibernate: select student0_.idas col_0_0_ from t_student student0_ * * 再依次发出依据id查询Student对象的sql语句 * Hibernate: select student0_.idas id1_0_, student0_.name as name1_0_, * student0_.createTime ascreateTime1_0_, student0_.classesid as classesid1_0_ * from t_student student0_ wherestudent0_.id=?*/ Iterator students =session.createQuery("fromStudent").iterate(); while (students.hasNext()){ Student student=(Student)students.next(); System.out.println(student.getName()); } tx.commit();
先运行query.list()。再运行query.iterate。这样不会出现N+1问题
由于list操作已经将Student对象放到了一级缓存中,所以再次使用iterate操作的时候
它首先发出一条查询id列表的sql。再依据id到缓存中取数据。仅仅有在缓存中找不到对应的
数据时,才会发出sql到数据库中查询
List students =session.createQuery("from Student").list(); for (Iterator iter =students.iterator();iter.hasNext();){ Student student=(Student)iter.next(); System.out.println(student.getName()); } System.out.println("---------------------------------------------------------"); // 不会出现N+1问题,由于list操作已经将数据增加到一级缓存。 Iterator iters=session.createQuery("from Student").iterate(); while (iters.hasNext()){ Student student=(Student)iters.next(); System.out.println(student.getName()); }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我们不能满足数据的要求本身就可以被认为是一个特定的导入工具
版权声明:本文博主原创文章,博客,未经同意不得转载。