Java EE SSH框架之hibernate(4)—— 查询优化

    本篇主要有get和load的类级别查询方法,懒加载原理,关联级别查询(集合级别,属性级别)中的fetch属性和lazy属性。

一、类级别查询

1.1、get方法和load方法

   

     get方法:使用get方法,立即加载,即执行该方法时,立即发送SQL语句查询结果。

     load方法(懒加载/延迟加载):默认情况下,在执行load方法时,不发送任何SQL语句,返回一个对象,而是在使用该对象时,才发送SQL查询。

     延迟加载:仅仅获得没有使用,不会查询,在使用时才会进行查询!

     上述说“load默认情况下”,对,load还可以不是默认情况,在ORM配置文件(×××.hbm.xml)中的class元素有一个lazy属性,默认为true,就是懒加载,若改为false,再使用load方法时它就“不懒了”,会立即加载,与get的效果完全相同!

!!!get方法就是单纯的立即加载,load才分两种情况,别弄混了!!!


1.2、load懒加载原理

     在上面使用load截图中的这一行加断点,debug一下,会发现Variables窗口看到对象c,它的value里包含有两个$符:


    如果之前学过动态代理就会知道,对象在打印时,若出现了$符,该对象就是一个代理对象(对自己的方法进行增强或改造)。所以这里对象c变成了一个代理对象(hibernate已经帮我们创建好了),对于现在这个c对象,不再是一个普通的Customer对象了,而是可以根据当前session,具有了查询数据库的功能

    c->handler->initialized属性的值为false,表示没有初始化,按F8往下继续执行一句,查询数据库了,initialized属性值立即变成了true。

   


注意:懒加载时,调用属性加载数据要确保session还是打开的(上面解释了,代理对象c是根据当前session查询数据库的)

在session关闭后使用c对象,会抛出如下异常:

    如果在session关闭前,使用了c对象,关闭后再使用session,这种情况下(如下图)不会报异常,因为c对象已经被初始化了,session关闭之后还是可以使用c对象的。不过这时的c对象是游离态,在事务中,不会有这种情况。



下面对于类级别查询的懒加载小结一下:

    lazy:为true(默认)时,查询类时,会返回代理对象,该对象会在使用属性时,根据关联的session查询数据库,加载数据;为false时,load方法与get方法没有区别,一调用就会加载数据。为了提高效率,建议使用懒加载!


二、关联级别查询

     这部分用了 上一篇搭建好的环境,看前请参考我 上一篇中的一对多关系的部分!!!

    上面的get和load方法都是根据id查询单表,太过于简单了。下面来分析关联级别的查询,集合关联查询又分为集合关联查询和属性关联级别查询。

2.1、集合关联级别查询

    在配置set元素时,它还有lazy属性和fetch属性,在集合关联查询中,这两个属性各有三个取值。

lazy(决定是否延迟加载):

true(默认值)——延迟加载    ②false——立即加载    ③extra——极其懒惰

fetch(决定加载策略,使用什么类型的SQL语句加载集合数据):

select(默认值)——单表查询加载    ②join——使用多表查询集合    ③subselect——使用子查询加载集合



2.1.1、单表查询(fetch="select")

(1)fetch="select" lazy="true"

先改一下Customer.hbm.xml里的set配置:

再测试(在19行和21 行分别加上了断点):

    分析:

    执行到19行,查询Customer,根据控制台打印情况,可以看出只加载了Customer,并没有加载linkMens;

        

    执行20行,获得linkMens,控制台打印结果没有任何变化;

    执行21行,使用LinkMens,控制台加载了LinkMens,并显示了结果。

        

小结:lazy为true时是懒加载,使用时才加载集合数据;上述SQL语句都是单表查询语句,所以fetch为select时是单表查询。



(2)fetch="select"  lazy="false"

改一下Customer.hbm.xml配置,测试代码不变:



分析:

执行19行,加载了Customer之后立即加载了linkMens;


执行20行,无变化;

执行21行,显示了结果。


小结:lazy为false时是立即加载集合数据;fetch为select时是单表查询。


(3)fetch="select" lazy="extra"


添加一行打印集合size的测试代码:


分析:

    执行32行,查询Customer,只加载了Customer,并没有加载linkMens;


   执行33行,无变化;

   执行34行,直接查询了集合的size,没有去加载linkMens;

执行35行,这时才加载了linkMens,并显示结果。


小结:lazy为extra时,极其懒惰和懒加载效果基本一致,如果只获得集合的size,就只查询集合的size(count语句),节省了很多资源;fetch为select时是单表查询。



2.1.2、单表查询(fetch="join")

(4)fetch="join" lazy="true"

为方便看到是多表查询,在主配置文件里设置了格式化SQL : <property name="hibernate.format_sql">true</property>

分析:

    执行32行,查询Customer,不仅加载了Customer,还加载了与Customer关联的linkMens;


    执行33,34,35行时没有打印SQL语句,而是直接打印了结果(SQL语句太长就没有截图):

        

小结:fetch为join时,为多表查询,此时,lazy属性设置为true/false/extra都一样,都是立即加载。

          简言之,fetch为join时,lazy属性失效!

(5)fetch="join" lazy="false"

(6)fetch="join" lazy="extra"

略过。。。。。。。。。。。。




2.1.3、子查询(fetch="subselect")

    子查询:查询嵌套,一个查询需要用到另一个查询的结果

    所有测试代码需要改变了

(7)fetch="subselect" lazy="true"

在51行设置断点

执行51行,打印了查询所有Customer的语句,并没有加载list集合;

执行54行,打印Customer;  

执行55行出现了子查询,这时使用到了list集合,才加载list集合;

小结:fetch为subselect时,为子查询,lazy属性设置为true,懒加载。


(8)fetch="subselect" lazy="false"

执行51行时,打印了查询所有Customer的语句,并加载list集合,(7)中两个很长的查询语句都一起打印了,太长了,就不再截图了;

小结:fetch为subselect时,为子查询,lazy属性设置为true,立即加载。


(9)fetch="subselect" lazy="extra"


与lazy=“true”不同的是:

在执行55行时,只打印了select count()语句,并未加载list,只有执行到了56行,才加载list


小结:lazy为extra时,极其懒惰和懒加载效果基本一致,如果只获得集合的size,就只查询集合的size(count语句);fetch为select时是子查询。



2.2、属性关联查询

     在LinkMan.hbm.xml配置如下(蓝色高亮部分),去掉Customer中对于这两个属性的配置!

    与集合关联不同的是,fetch只有两个取值,没有子查询,且lazy三个取值也和集合关联的不同,具体如下:

lazy(决定是否延迟加载):

proxy(默认值)——"别人替我"决定    ②false——立即加载    ③no-proxy(略过)

(用例子解释一下proxy值:由Customer的类级别加载策略决定,即Customer配置文件中class元素的lazy属性决定)

fetch(决定加载策略,使用什么类型的SQL语句加载集合数据):

select(默认值)——单表查询加载    ②join——使用多表查询集合

这里我们只考虑以下四种情况:



2.2.1、单表查询

(1)fetch="select" lazy="proxy"(都是默认值)


测试代码:


**************Customer配置文件中class属性配置lazy为“true”:***********************


分析:

    执行68行,加载了LinkMan,并未加载Customer;


    执行69行,无变化;执行70行,使用到了Customer,才加载Customer。


***********************Customer配置文件中class属性配置lazy为“false”:***********************


分析:

    执行68行,加载了LinkMan后马上加载Customer;


    小结:fetch值为select表示单表查询毋庸置疑,lazy属性为proxy时,是根据Customer配置文件中class元素的lazy属性决定的,lazy为true时就是懒加载,为false就是立即加载。


(2)fetch="select"  lazy="false"

与(1)中Customer配置文件中class元素的lazy取“false”一样,都是立即加载。


2.2.2、多表查询

和集合关联查询中多表查询一样,此时lazy属性已经失效了!



总结:为了提高效率,fetch的选择上应该选择select,lazy的取值应该选择true,即全部选择默认值!







评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值