Hibernate--fetch抓取策略
2016-01-08 15:16
495 查看
有几个需要注意的地方:
1 在xml配置中 是默认懒加载的(fetch=select),也就是在使用到懒加载对象的属性时候 才会发出SQL语句,不使用的话就发一个SQL即可,若遍历时使用关联对象的属性,那么会发出大量SQL,而这是我们不希望看见的
很多情况下 我们是要希望能使用fetch=Join 也就是实现全部加载 只发出一条SQL,即使没有显示的使用关联对象属性仍然全部加载,此SQL使用left join连接表。省的在遍历时调用关联对象属性的时候 再发出大量SQL 给数据库造成巨大压力(反正是要把数据都取出来的)
2 annatation中是默认对象fetchType=eager 也就是join 而不是select懒加载,即全部加载
3 这是加载多端对象 想要加载全部
默认在xml中会发出3条SQL语句 一条区student 一条取classroom 一条取special
通过设置student的xml中的<many-to-one name="classroom" column="cid" fetch="join"/>
同样要对classroom进行设置 join抓取special
可以完成对抓取的设置
这样也会占用内存 数据库等资源
此时延迟加载就失效了
所以此时使用默认方式fetch=select
从多端级联查询一端解决方案2中:
1设置对象抓取的batch size在班级中设置 比如=20 表示加载student对象时一次取20个班 默认是一次一个班
相当于一下子把关联的很多班级都取了出来 功能上=fetch=join
<class name="Classroom" table="t_cla" batch-size="3">
但是占内存多 且session关闭额 就数据消失了
这是加载关联对象时候只会发出一条SQL 但是join fetch不能和count(*)同时使用 我们计数时候 把fetch去掉就是了
6对于从一端加载的情况 从一端fetch的情况 默认延迟加载
在一端加batch-size=3 表示3个一端对象对应的所有多端对象全部加载 比如3个班的所有学生加载 减少发出的SQL
同理: 一对多时候 从一端延迟加载多端对象 在一端set中batch-size="3"表示3个一端对象对应的所有多端对象全部延迟加载
8 对于通过HQL取班级列表并且获取相应学生列表时候 fetch=join 就无效 还是select懒加载模式
(一端取被多端关联的对象 注意和第五条区别) 2种方案解决这个问题 因为我们的目的是要尽可能一次性全部加载(通过join连接) 不要懒加载(每用一次发个SQL)
1 在一的一端set中加入batch-size 见test08
这是个非常好的解决方法 1条SQL搞定 很好
9 batsize都是在一端设置 多级联查询一时候 在xml的class上添加 ,一级联查询多时候 在set 上添加
下面是配置文件和 测试代码
1 在xml配置中 是默认懒加载的(fetch=select),也就是在使用到懒加载对象的属性时候 才会发出SQL语句,不使用的话就发一个SQL即可,若遍历时使用关联对象的属性,那么会发出大量SQL,而这是我们不希望看见的
很多情况下 我们是要希望能使用fetch=Join 也就是实现全部加载 只发出一条SQL,即使没有显示的使用关联对象属性仍然全部加载,此SQL使用left join连接表。省的在遍历时调用关联对象属性的时候 再发出大量SQL 给数据库造成巨大压力(反正是要把数据都取出来的)
2 annatation中是默认对象fetchType=eager 也就是join 而不是select懒加载,即全部加载
3 这是加载多端对象 想要加载全部
默认在xml中会发出3条SQL语句 一条区student 一条取classroom 一条取special
通过设置student的xml中的<many-to-one name="classroom" column="cid" fetch="join"/>
同样要对classroom进行设置 join抓取special
可以完成对抓取的设置
session=HibernateUtil.openSession(); Student stu=(Student)session.load(Student.class,1); System.err.println(stu.getName()+","+ stu.getClassroom().getName()+","+stu.getClassroom().getSpecial().getName());4 使用fetch=join虽然可以把关联的对象全部抓取出来 但是如果不使用关联对象 也会一并查询出来
这样也会占用内存 数据库等资源
此时延迟加载就失效了
<span style="white-space:pre"> </span> session=HibernateUtil.openSession(); Student stu=(Student)session.load(Student.class,2); System.err.println(stu.getName());5 因为fetch=join仅仅对Load时候有用 对HQL没有作用 用到了再发SQL
所以此时使用默认方式fetch=select
从多端级联查询一端解决方案2中:
1设置对象抓取的batch size在班级中设置 比如=20 表示加载student对象时一次取20个班 默认是一次一个班
相当于一下子把关联的很多班级都取了出来 功能上=fetch=join
<class name="Classroom" table="t_cla" batch-size="3">
但是占内存多 且session关闭额 就数据消失了
<span style="white-space:pre"> </span>List<Student> stus=session.createQuery("from Student").list(); for (Student student : stus) { System.out.println(student.getName()+student.getClassroom()); }2 重要 :在HQL中使用fetch来指定抓取 可以做到只对关联对象查一次 完全类似join在Load中的功能
这是加载关联对象时候只会发出一条SQL 但是join fetch不能和count(*)同时使用 我们计数时候 把fetch去掉就是了
session=HibernateUtil.openSession(); List<Student> stus=session.createQuery("select stu from Student stu join fetch stu.classroom").list(); for (Student student : stus) { System.out.println(student.getName()+student.getClassroom()); }
6对于从一端加载的情况 从一端fetch的情况 默认延迟加载
session=HibernateUtil.openSession(); Classroom cla=(Classroom)session.load(Classroom.class,1); System.out.println(cla.getName());//延迟加载发出一条SQL for (Student student : cla.getStudents())//延迟加载 cla.getStudents()会发一条SQL 取出所有students { System.out.println(student.getName()); }7 注意:多对一时候 从多端懒加载一对象(目的是为了全部加载多端对象)
在一端加batch-size=3 表示3个一端对象对应的所有多端对象全部加载 比如3个班的所有学生加载 减少发出的SQL
同理: 一对多时候 从一端延迟加载多端对象 在一端set中batch-size="3"表示3个一端对象对应的所有多端对象全部延迟加载
8 对于通过HQL取班级列表并且获取相应学生列表时候 fetch=join 就无效 还是select懒加载模式
(一端取被多端关联的对象 注意和第五条区别) 2种方案解决这个问题 因为我们的目的是要尽可能一次性全部加载(通过join连接) 不要懒加载(每用一次发个SQL)
1 在一的一端set中加入batch-size 见test08
<set name="students" inverse="true" lazy="extra" fetch="subselect" batch-size="2"> <key column="cid" /> <one-to-many class="Student"/> </set>2 第二种方案可以设置fetch=sub-select 通过子查询 自动查出的班级再通过子查询查所有对应的学生
这是个非常好的解决方法 1条SQL搞定 很好
9 batsize都是在一端设置 多级联查询一时候 在xml的class上添加 ,一级联查询多时候 在set 上添加
下面是配置文件和 测试代码
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.itany.model"> <class name="Student" table="t_stu"> <!-- <cache usage="read-only" /> --> <id name="id"> <generator class="native"></generator> </id> <!-- 注意:version 一定要加在ID后面 property前面 --> <version name="version" /> <property name="name" /> <property name="sex" /> <many-to-one name="classroom" column="cid" fetch="join" /> </class> </hibernate-mapping>
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.itany.model"> <!-- 注意:多对一时候 从多端懒加载一对象(目的是为了全部加载多端对象) 在一端加batch-size=3 表示3个一端对象对应的所有多端对象全部加载 比如3个班的所有学生加载 减少发出的SQL 同理: 一对多时候 从一端延迟加载多端对象 在一端set中batch-size="3"表示3个一端对象对应的所有多端对象全部延迟加载--> <class name="Classroom" table="t_cla" batch-size="3"> <id name="id" > <generator class="native"></generator> </id> <property name="name" /> <property name="grade" /> <!-- 表示一次加载2个classroom的所有学生 --> <set name="students" inverse="true" lazy="extra" fetch="subselect" batch-size="2"> <key column="cid" /> <one-to-many class="Student"/> </set> <many-to-one name="special" column="spec_id" fetch="join"/> </class> </hibernate-mapping>
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.itany.model"> <class name="Special" table="t_spec"> <id name="id" > <generator class="native"></generator> </id> <property name="name" /> <property name="type" /> <set name="clas" inverse="true" lazy="extra"> <key column="spec_id" /> <one-to-many class="Classroom" /> </set> </class> </hibernate-mapping>
public class TestFetch
{
@Test
public void test01()
{
Session session=null;
Transaction trans=null;
try
{
/*
* 默认在xml中会发出3条SQL语句 一条区student 一条取classroom 一条取special
* 通过设置student的xml中的<many-to-one name="classroom" column="cid" fetch="join"/>
* 同样要对classroom进行设置 join抓取special
* 可以完成对抓取的设置
*/
session=HibernateUtil.openSession(); Student stu=(Student)session.load(Student.class,1); System.err.println(stu.getName()+","+ stu.getClassroom().getName()+","+stu.getClassroom().getSpecial().getName());
}
catch (HibernateException e)
{
e.printStackTrace();
}
finally
{
if(null!=session)
HibernateUtil.closeSession(session);
}
}
@Test
public void test02()
{
Session session=null;
Transaction trans=null;
try
{
/*
* 使用fetch=join虽然可以把关联的对象全部抓取出来 但是如果不使用关联对象 也会一并查询出来
* 这样也会占用内存 数据库等资源
* 此时延迟加载就失效了
*/
session=HibernateUtil.openSession();
Student stu=(Student)session.load(Student.class,2);
System.err.println(stu.getName());
}
catch (HibernateException e)
{
e.printStackTrace();
}
finally
{
if(null!=session)
HibernateUtil.closeSession(session);
}
}
@Test
public void test03()
{
Session session=null;
Transaction trans=null;
try
{
/*
* 此时虽然在xml中设置了fetch=join 结果仍然发出了取classroom得SQL语句 没有合并成一句执行(即立即全部查出关联对象)
* 因为fetch=join仅仅对Load时候有用 对HQL没有作用 用到了再发
* 所以此时使用默认方式fetch=select 所以此时发出查询班级的SQL
*
* 解决方案:2种
* 1 设置对象抓取的batch size在班级中设置 比如=20 表示加载student对象时一次取20个班 默认是一次一个班
* 相当于一下子把关联的很多班级都取了出来 功能上=fetch=join
* <class name="Classroom" table="t_cla" batch-size="3">
* 但是占内存多 且session关闭额 就数据消失了
* 2 重要 :在HQL中使用fetch来指定抓取 可以做到只对关联对象查一次 完全类似join在Load中的功能
* 例子见test04
*/
session=HibernateUtil.openSession();
List<Student> stus=session.createQuery("from Student").list();
for (Student student : stus)
{
System.out.println(student.getName()+student.getClassroom());
}
}
catch (HibernateException e)
{
e.printStackTrace();
}
finally
{
if(null!=session)
HibernateUtil.closeSession(session);
}
}
@Test
public void test04()
{
Session session=null;
Transaction trans=null;
try
{
/*
* 此时在普通的from Student stu join fetch stu.classroom
* 这是加载关联对象时候只会发出一条SQL
* 但是join fetch不能和count(*)同时使用
* 我们计数时候 把fetch去掉就是了
*/
session=HibernateUtil.openSession(); List<Student> stus=session.createQuery("select stu from Student stu join fetch stu.classroom").list(); for (Student student : stus) { System.out.println(student.getName()+student.getClassroom()); }
}
catch (HibernateException e)
{
e.printStackTrace();
}
finally
{
if(null!=session)
HibernateUtil.closeSession(session);
}
}
//从一端fetch的情况 默认延迟加载
@Test
public void test05()
{
Session session=null;
Transaction trans=null;
try
{
/*
*/
session=HibernateUtil.openSession(); Classroom cla=(Classroom)session.load(Classroom.class,1); System.out.println(cla.getName());//延迟加载发出一条SQL for (Student student : cla.getStudents())//延迟加载 cla.getStudents()会发一条SQL 取出所有students { System.out.println(student.getName()); }
}
catch (HibernateException e)
{
e.printStackTrace();
}
finally
{
if(null!=session)
HibernateUtil.closeSession(session);
}
}
//双向:以下都是。从一端fetch的情况 fetch=join
@Test
public void test06()
{
Session session=null;
Transaction trans=null;
try
{
/*
*/
session=HibernateUtil.openSession();
Classroom cla=(Classroom)session.load(Classroom.class,1);
System.out.println(cla.getName());//一共就一条SQL 此时全部加载关联对象 虽然没有显示调用
for (Student student : cla.getStudents())//
{
System.out.println(student.getName());
}
}
catch (HibernateException e)
{
e.printStackTrace();
}
finally
{
if(null!=session)
HibernateUtil.closeSession(session);
}
}
@Test
public void test07()
{
Session session=null;
Transaction trans=null;
try
{
/*对于通过HQL取班级列表并且获取相应学生列表时候 fetch=join 就无效 还是select懒加载模式
* 2种方案解决这个问题 因为我们的目的是要尽可能一次性全部加载(通过join连接) 不要懒加载(每用一次发个SQL)
* 1 在一的一端set中加入batch-size 见test08
* 2 第二种方案可以设置fetch=sub-select 通过子查询 自动查出的班级再通过子查询查所有对应的学生
* 这是个非常好的解决方法 1条SQL搞定 很好
*/
session=HibernateUtil.openSession();
List<Classroom> clas=session.createQuery("from Classroom").list();//执行完这步 会发一句SQL 查询所有classroom
for (Classroom classroom : clas)
{
System.out.println(classroom.getName());
for (Student student : classroom.getStudents())//每一个classroom懒加载该id的所有学生 一共发出10次 因为有10个班级
{
System.out.println(student.getName());
}
}
}
catch (HibernateException e)
{
e.printStackTrace();
}
finally
{
if(null!=session)
HibernateUtil.closeSession(session);
}
}
@Test
public void test08()
{
Session session=null;
Transaction trans=null;
try
{
/*在classroom 中set中设置batch-size=2 在一的一端进行设置
*/
session=HibernateUtil.openSession();
List<Classroom> clas=session.createQuery("from Classroom").list();//
for (Classroom classroom : clas)
{
System.out.println(classroom.getName());
for (Student student : classroom.getStudents())//
//
{
System.out.println(student.getName());//
}
}
}
catch (HibernateException e)
{
e.printStackTrace();
}
finally
{
if(null!=session)
HibernateUtil.closeSession(session);
}
}
}
相关文章推荐
- Html5添加支持桌面、移动触摸手机和平板电脑的Lightbox插件教程
- Javascript关闭Chrome等所有浏览器的方法
- LeetCode_237. Delete Node in a Linked List
- 谷歌浏览器开发调试工具中Sources面板 js调试等 完全介绍
- LeetCode_237. Delete Node in a Linked List
- JavaScript基本概念(五)---语句和函数
- React Native探索(六)不止是UI:React的使用场景探索
- jquery获取自定义的标签属性的值
- React Native探索(五):使用Flux搭建React应用程序架构
- ajax Json 应用
- js 四舍五入
- React Native探索(四):虚拟DOM Diff算法解析
- 玩转Json
- js--获取和设置css属性
- co.js 学习,以及自己简单实现
- HTML元素的显示优先级
- js--获取和设置css属性
- React Native探索(三):与 react-web 的融合
- React Native探索(二):布局篇
- CSS3:linear-gradient,线性渐变的使用方法