Hibernate 抓取策略fetch-2 (批量抓取batch-size以及hibernate.jdbc.fetch_size、hibernate.jdbc.batch_size)
类关系: User N~1 Group
测试代码:
- System.out.println("1");
- List stuList = session.createQuery("from User s where s.password ='123'").list(); //(1)
- System.out.println("2");
- for(Iterator it = stuList.iterator(); it.hasNext();){
- User stu = (User)it.next();
- System.out.println("3");
- System.out.println("[value]"+stu.getName()); //(2)
- System.out.println("[value]"+stu.getGroup().getName()); //(3)
- }
执行效果:
(1)查询符合条件的User集合. 发出的SQL为 select * from test_User where password='123'
(2)不再发出SQL. 使用缓存中的User数据.
(3)迭代User时,检查是否加载过对应User的Group,若无则发出一次SQL: select * from test_group where group_id=?
如果User有10个.对应在3个group中. 则发出3条select * from test_group where group_id=?
Hibernate:
select
user0_.id as id0_,
user0_.name as name0_,
user0_.password as password0_,
user0_.createTime as createTime0_,
user0_.updateTime as updateTime0_,
user0_.group_id as group6_0_
from
TEST_User user0_
where
user0_.password='123'
2
3
[value]jordan
Hibernate:
select
group0_.id as id1_0_,
group0_.name as name1_0_
from
TEST_Group group0_
where
group0_.id=?
[value]集团2
3
[value]kobe
[value]集团2
3
[value]james
[value]集团2
3
[value]张三111
Hibernate:
select
group0_.id as id1_0_,
group0_.name as name1_0_
from
TEST_Group group0_
where
group0_.id=?
[value]集团1
3
[value]李四111
[value]集团1
3
[value]李四111
[value]集团1
3
[value]AAA
Hibernate:
select
group0_.id as id1_0_,
group0_.name as name1_0_
from
TEST_Group group0_
where
group0_.id=?
[value]集团3
3
[value]BBB
[value]集团3
3
[value]CCC
[value]集团3
3
[value]a1
Hibernate:
select
group0_.id as id1_0_,
group0_.name as name1_0_
from
TEST_Group group0_
where
group0_.id=?
[value]集团4
3
[value]a11
[value]集团4
3
[value]a111
[value]集团4
3
[value]b1
Hibernate:
select
group0_.id as id1_0_,
group0_.name as name1_0_
from
TEST_Group group0_
where
group0_.id=?
[value]集团5
3
[value]b11
[value]集团5
3
[value]b111
[value]集团5
配置batch-size
<class name="com.test.entity.Group" table="TEST_Group" batch-size="2">
执行效果
(1)(2)同上
(3)在遍历User,并且获取对应的Group时.检测是否加载过对应的数据.若无根据设置的batch-size=2
发出SQL语句: select * from test_group where group_id in (?,?) 一次查询2个Group放到内存中.
在此遍历User及其Group时,若内存中无加载过对应数据,则再次发出SQL select * from test_group where group_id in (?,?) 一次查询2个Group放到内存中.
如Group的数据最后不足.则使用select * from test_group where group_id =? 进行加载
即如Group 有5个. 则通过2个2个1个的方式进行查询获取到.
- 1
- Hibernate:
- select
- user0_.id as id0_,
- user0_.name as name0_,
- user0_.password as password0_,
- user0_.createTime as createTime0_,
- user0_.updateTime as updateTime0_,
- user0_.group_id as group6_0_
- from
- TEST_User user0_
- where
- user0_.password='123'
- 2
- 3
- [value]jordan
- Hibernate:
- select
- group0_.id as id1_0_,
- group0_.name as name1_0_
- from
- TEST_Group group0_
- where
- group0_.id in (
- ?, ?
- )
- [value]集团2
- 3
- [value]kobe
- [value]集团2
- 3
- [value]james
- [value]集团2
- 3
- [value]张三111
- [value]集团1
- 3
- [value]李四111
- [value]集团1
- 3
- [value]李四111
- [value]集团1
- 3
- [value]AAA
- Hibernate:
- select
- group0_.id as id1_0_,
- group0_.name as name1_0_
- from
- TEST_Group group0_
- where
- group0_.id in (
- ?, ?
- )
- [value]集团3
- 3
- [value]BBB
- [value]集团3
- 3
- [value]CCC
- [value]集团3
- 3
- [value]a1
- [value]集团4
- 3
- [value]a11
- [value]集团4
- 3
- [value]a111
- [value]集团4
- 3
- [value]b1
- Hibernate:
- select
- group0_.id as id1_0_,
- group0_.name as name1_0_
- from
- TEST_Group group0_
- where
- group0_.id=?
- [value]集团5
- 3
- [value]b11
- [value]集团5
- 3
- [value]b111
- [value]集团5
P.S 注意如果使用iterate进行迭代而非List ,则Batch-size无效.
如下
- System.out.println("1");
- Iterator iter = session.createQuery(" from Group g where g.name like'集团%'").iterate(); //(1)
- System.out.println("2");
- while (iter.hasNext()) {
- System.out.println("3");
- Group g = (Group) iter.next();
- System.out.println("4");
- System.out.println("[value]" + g.getName()); //(2)
- System.out.println("5");
- System.out.println("[value]" + g.getUsers().size()); //(3)
- }
执行效果
原因的出现是因为
(1)处使用了iterate返回集合.iterate默认会开始发出一条语句:查询所有记录符合条件的user的ID. select id from user where password =?
因为(1)只查询出id , 所以在(2)时. 需要再发出一条SQL获取user的属性数据. select * from user where id=?
这就是iterate很出名的N+1问题.
至于(3)处, 如果group没加载过,每次都会发出一条SQL. select * from group where id=?
所以此情况下, batch-size已无法达到预期效果.
- 1
- Hibernate:
- select
- user0_.id as col_0_0_
- from
- TEST_User user0_
- where
- user0_.password='123'
- 2
- 3
- 4
- Hibernate:
- select
- user0_.id as id0_0_,
- user0_.name as name0_0_,
- user0_.password as password0_0_,
- user0_.createTime as createTime0_0_,
- user0_.updateTime as updateTime0_0_,
- user0_.group_id as group6_0_0_
- from
- TEST_User user0_
- where
- user0_.id=?
- [value]jordan
- 5
- Hibernate:
- select
- group0_.id as id1_0_,
- group0_.name as name1_0_
- from
- TEST_Group group0_
- where
- group0_.id=?
- [value]集团2
- 3
- 4
- Hibernate:
- select
- user0_.id as id0_0_,
- user0_.name as name0_0_,
- user0_.password as password0_0_,
- user0_.createTime as createTime0_0_,
- user0_.updateTime as updateTime0_0_,
- user0_.group_id as group6_0_0_
- from
- TEST_User user0_
- where
- user0_.id=?
- [value]kobe
- 5
- [value]集团2
- 3
- 4
- Hibernate:
- select
- user0_.id as id0_0_,
- user0_.name as name0_0_,
- user0_.password as password0_0_,
- user0_.createTime as createTime0_0_,
- user0_.updateTime as updateTime0_0_,
- user0_.group_id as group6_0_0_
- from
- TEST_User user0_
- where
- user0_.id=?
- [value]james
- 5
- [value]集团2
- 3
- 4
- Hibernate:
- select
- user0_.id as id0_0_,
- user0_.name as name0_0_,
- user0_.password as password0_0_,
- user0_.createTime as createTime0_0_,
- user0_.updateTime as updateTime0_0_,
- user0_.group_id as group6_0_0_
- from
- TEST_User user0_
- where
- user0_.id=?
- [value]张三111
- 5
- Hibernate:
- select
- group0_.id as id1_0_,
- group0_.name as name1_0_
- from
- TEST_Group group0_
- where
- group0_.id=?
- [value]集团1
- 3
- 4
- Hibernate:
- select
- user0_.id as id0_0_,
- user0_.name as name0_0_,
- user0_.password as password0_0_,
- user0_.createTime as createTime0_0_,
- user0_.updateTime as updateTime0_0_,
- user0_.group_id as group6_0_0_
- from
- TEST_User user0_
- where
- user0_.id=?
- [value]李四111
- 5
- [value]集团1
- 3
- 4
- Hibernate:
- select
- user0_.id as id0_0_,
- user0_.name as name0_0_,
- user0_.password as password0_0_,
- user0_.createTime as createTime0_0_,
- user0_.updateTime as updateTime0_0_,
- user0_.group_id as group6_0_0_
- from
- TEST_User user0_
- where
- user0_.id=?
- [value]李四111
- 5
- [value]集团1
- 3
- 4
- Hibernate:
- select
- user0_.id as id0_0_,
- user0_.name as name0_0_,
- user0_.password as password0_0_,
- user0_.createTime as createTime0_0_,
- user0_.updateTime as updateTime0_0_,
- user0_.group_id as group6_0_0_
- from
- TEST_User user0_
- where
- user0_.id=?
- [value]AAA
- 5
- Hibernate:
- select
- group0_.id as id1_0_,
- group0_.name as name1_0_
- from
- TEST_Group group0_
- where
- group0_.id=?
- [value]集团3
- 3
- 4
- Hibernate:
- select
- user0_.id as id0_0_,
- user0_.name as name0_0_,
- user0_.password as password0_0_,
- user0_.createTime as createTime0_0_,
- user0_.updateTime as updateTime0_0_,
- user0_.group_id as group6_0_0_
- from
- TEST_User user0_
- where
- user0_.id=?
- [value]BBB
- 5
- [value]集团3
- 3
- 4
- Hibernate:
- select
- user0_.id as id0_0_,
- user0_.name as name0_0_,
- user0_.password as password0_0_,
- user0_.createTime as createTime0_0_,
- user0_.updateTime as updateTime0_0_,
- user0_.group_id as group6_0_0_
- from
- TEST_User user0_
- where
- user0_.id=?
- [value]CCC
- 5
- [value]集团3
- 3
- 4
- Hibernate:
- select
- user0_.id as id0_0_,
- user0_.name as name0_0_,
- user0_.password as password0_0_,
- user0_.createTime as createTime0_0_,
- user0_.updateTime as updateTime0_0_,
- user0_.group_id as group6_0_0_
- from
- TEST_User user0_
- where
- user0_.id=?
- [value]a1
- 5
- Hibernate:
- select
- group0_.id as id1_0_,
- group0_.name as name1_0_
- from
- TEST_Group group0_
- where
- group0_.id=?
- [value]集团4
- 3
- 4
- Hibernate:
- select
- user0_.id as id0_0_,
- user0_.name as name0_0_,
- user0_.password as password0_0_,
- user0_.createTime as createTime0_0_,
- user0_.updateTime as updateTime0_0_,
- user0_.group_id as group6_0_0_
- from
- TEST_User user0_
- where
- user0_.id=?
- [value]a11
- 5
- [value]集团4
- 3
- 4
- Hibernate:
- select
- user0_.id as id0_0_,
- user0_.name as name0_0_,
- user0_.password as password0_0_,
- user0_.createTime as createTime0_0_,
- user0_.updateTime as updateTime0_0_,
- user0_.group_id as group6_0_0_
- from
- TEST_User user0_
- where
- user0_.id=?
- [value]a111
- 5
- [value]集团4
- 3
- 4
- Hibernate:
- select
- user0_.id as id0_0_,
- user0_.name as name0_0_,
- user0_.password as password0_0_,
- user0_.createTime as createTime0_0_,
- user0_.updateTime as updateTime0_0_,
- user0_.group_id as group6_0_0_
- from
- TEST_User user0_
- where
- user0_.id=?
- [value]b1
- 5
- Hibernate:
- select
- group0_.id as id1_0_,
- group0_.name as name1_0_
- from
- TEST_Group group0_
- where
- group0_.id=?
- [value]集团5
- 3
- 4
- Hibernate:
- select
- user0_.id as id0_0_,
- user0_.name as name0_0_,
- user0_.password as password0_0_,
- user0_.createTime as createTime0_0_,
- user0_.updateTime as updateTime0_0_,
- user0_.group_id as group6_0_0_
- from
- TEST_User user0_
- where
- user0_.id=?
- [value]b11
- 5
- [value]集团5
- 3
- 4
- Hibernate:
- select
- user0_.id as id0_0_,
- user0_.name as name0_0_,
- user0_.password as password0_0_,
- user0_.createTime as createTime0_0_,
- user0_.updateTime as updateTime0_0_,
- user0_.group_id as group6_0_0_
- from
- TEST_User user0_
- where
- user0_.id=?
- [value]b111
- 5
- [value]集团5
hibernate.jdbc.fetch_size 和 hibernate.jdbc.batch_size
摘自:http://dongruan00.iteye.com/blog/1835081
hibernate.jdbc.fetch_size 50 //读
hibernate.jdbc.batch_size 30 //写
hiberante.cfg.xml(Oracle ,sql server 支持,mysql不支持)
配置文件参考如下:
<property name="hibernate.jdbc.fetch_size">50</property>
<property name="hibernate.jdbc.batch_size">30</property>
这两个选项非常非常非常重要!!!将严重影响Hibernate的CRUD性能!
C = create, R = read, U = update, D = delete
Fetch Size 是设定JDBC的Statement读取数据的时候每次从数据库中取出的记录条数。
例如一次查询1万条记录,对于Oracle的JDBC驱动来说,是不会1次性把1万条取出来的,而只会取出Fetch Size条数,当纪录集遍历完了这些记录以后,再去数据库取Fetch Size条数据。因此大大节省了无谓的内存消耗。当然Fetch Size设的越大,读数据库的次数越少,速度越快;Fetch Size越小,读数据库的次数越多,速度越慢。这有点像平时我们写程序写硬盘文件一样,设立一个Buffer,每次写入Buffer,等Buffer满了以后,一次写入硬盘,道理相同。
Oracle数据库的JDBC驱动默认的Fetch Size=10,是一个非常保守的设定,根据我的测试,当Fetch Size=50的时候,性能会提升1倍之多,当Fetch Size=100,性能还能继续提升20%,Fetch Size继续增大,性能提升的就不显著了。
因此我建议使用Oracle的一定要将Fetch Size设到50。
不过并不是所有的数据库都支持Fetch Size特性,例如MySQL就不支持。
MySQL就像我上面说的那种最坏的情况,他总是一下就把1万条记录完全取出来,内存消耗会非常非常惊人!这个情况就没有什么好办法了 :(
Batch Size是设定对数据库进行批量删除,批量更新和批量插入的时候的批次大小,有点相当于设置Buffer缓冲区大小的意思。
Batch Size越大,批量操作的向数据库发送sql的次数越少,速度就越快。我做的一个测试结果是当Batch Size=0的时候,使用Hibernate对Oracle数据库删除1万条记录需要25秒,Batch Size = 50的时候,删除仅仅需要5秒!!!
我们通常不会直接操作一个对象的标识符(identifier), 因此标识符的setter方法应该被声明为私有的(private)。这样当一个对象被保存的时候,只有Hibernate可以为它分配标识符。 你会发现Hibernate可以直接访问被声明为public,private和protected等不同级别访问控制的方法(accessor method)和字段(field)。 所以选择哪种方式来访问属性是完全取决于你,你可以使你的选择与你的程序设计相吻合。
所有的持久类(persistent classes)都要求有无参的构造器(no-argument constructor); 因为Hibernate必须要使用Java反射机制(Reflection)来实例化对象。构造器(constructor)的访问控制可以是私有的(private), 然而当生成运行时代理(runtime proxy)的时候将要求使用至少是package级别的访问控制,这样在没有字节码编入 (bytecode instrumentation)的情况下,从持久化类里获取数据会更有效率一些。
而 hibernate.max_fetch_depth 设置外连接抓取树的最大深度
取值. 建议设置为0到3之间
就是每次你在查询时,会级联查询的深度,譬如你对关联vo设置了eager的话,如果fetch_depth值太小的话,会发多很多条sql
Hibernate 抓取策略fetch-2 (批量抓取batch-size以及hibernate.jdbc.fetch_size、hibernate.jdbc.batch_size)的更多相关文章
- Hibernate之加载策略(延迟加载与即时加载)和抓取策略(fetch)
假设现在有Book和Category两张表,表的关系为双向的一对多,表结构如下: 假设现在我想查询id为2的那本书的书名,使用session.get(...)方法: Session session=H ...
- python动态网页爬取——四六级成绩批量爬取
需求: 四六级成绩查询网站我所知道的有两个:学信网(http://www.chsi.com.cn/cet/)和99宿舍(http://cet.99sushe.com/),这两个网站采用的都是动态网页. ...
- 【Hibernate 8】Hibernate的调优方法:抓取策略
在上一篇博客中,介绍了Hibernate的缓存机制.合理的配置缓存,可以极大程度上优化Hibernate的性能.这篇博客,介绍另外一个调优方式:抓取策略. 一.什么是抓取策略 抓取策略(fetchin ...
- 029 hibernate抓取策略
实例A引用实例B,B如果是代理的话(比如多对一关联中):如果遍历A的查询结果集(假设有10条记录),在遍历A的时候,访问B变量,将会导致n次查询语句的发出!这个时候,如果在B一端的class上配置ba ...
- Hibernate框架笔记04HQL_QBC查询详解_抓取策略优化机制
目录 1. Hibernate的查询方式 1.1 方式一:OID查询 1.2 方式二:对象导航查询 1.3 方式三:HQL方式 1.4 方式四:QBC查询 1.5 方式五:SQL查询 2. 环境搭建 ...
- Hibernate的抓取策略(优化)
延迟加载的概述 什么是延迟加载 延迟加载:lazy(懒加载).执行到该行代码的时候,不会发送语句去进行查询,在真正使用这个对象的属性的时候才会发送SQL语句进行查询. 延迟加载的分类 l 类级别的延 ...
- 【转】Hibernate 原汁原味的四种抓取策略
最近在研究 Hibernate 的性能优化的时候碰到了"抓取策略", 由于以前没有详细的研究过, 所以到处找资料, 但是无论从一些讲 Hibernate 书籍,还是他人 Blog ...
- Hibernate 原汁原味的四种抓取策略(转)
原文出处:http://www.cnblogs.com/rongxh7/archive/2010/05/12/1733088.html 尊重原作者,访问原创地址 最近在研究 Hibernate ...
- java:Hibernate框架4(延迟加载(lazy),抓取(fetch),一级缓存,get,load,list,iterate,clear,evict,flush,二级缓存,注解,乐观锁和悲观锁,两者的比较)
1.延时加载和抓取: hibernate.cfg.xml: <?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE hibernate-co ...
- hibernate抓取策略
抓取策略(fetching strategy) 是指:当应用程序需要在(Hibernate实体对象图的)关联关系间进行导航的时候, Hibernate如何获取关联对象的策略.抓取策略可以在O/R映射的 ...
随机推荐
- 即使连网了ping也会失败
/*************************************************************************** * 即使连网了ping也会失败 * 说明: * ...
- struts2 中的 result 返回类型是 json 的配置问题
struts2 中的 result 返回类型是 json 的配置问题 1.引入包(本文中的包全部引自struts-2.1.8.1\lib): struts2-json-plugin-2.1.8.1.j ...
- 图像处理之image stitching
背景介绍 图像拼接是一项应用广泛的图像处理技术.根据特征点的相互匹配,可以将多张小视角的图像拼接成为一张大视角的图像,在广角照片合成.卫星照片处理.医学图像处理等领域都有应用.早期的图像拼接主要是运用 ...
- C 语言中 free() 函数简单分析
又是一个睡不着的夜晚,现在是凌晨03:16,不知道是不是感冒的原因,头脑并不是清醒,但是就是睡不着.摸着黑打开电脑,洗了杯子抓了点茶叶,然后打开饮水机电源.舍友们都睡着了,我戴着耳机听着轻音乐,也能听 ...
- Android项目——电话拨号器
因为应用要使用手机的电话服务,所以要在清单文件AndroidManifest.xml中添加电话服务权限: <?xml version="1.0" encoding=" ...
- html5图片懒加载
http://www.178.com/s/js/jquery.lazyload.min.js
- awesome-nlp
awesome-nlp A curated list of resources dedicated to Natural Language Processing Maintainers - Keon ...
- C#代码:用事件模式实现通知
事件提供了一种标准的机制来通知监听者..NET的事件模式使用了事件语法来实现观察者模式.任意数量的客户对象都可以将自己的处理函数注册到事件上,然后处理这些事件.这些客户对象不需要再编译期就给出.时间也 ...
- postgreSQL 时间线
“时间线”(Timeline)是PG一个很有特色的概念,在备份恢复方面的文档里面时有出现.但针对这个概念的详细解释却很少,也让人不太好理解,我们在此仔细解析一下. 时间线的引入 为了理解引入时间线的背 ...
- C#综合揭秘——深入分析委托与事件
http://www.cnblogs.com/leslies2/archive/2012/03/22/2389318.html 引言 本篇文章将为你介绍一下 Delegate 的使用方式,逐渐揭开 C ...