hibernate 单双向N-1 1-N检索策略以及懒加载解决方案总结

 

  本例子表为 Students 表和Classes 表 其中 Students 表与Classes表的管理关系为单向N-1

单向N-1检索:
        在N的一方加入 lazy="false" ,即在做查询时 将与N关联的表全部查询出来(立即检索)

代码:

Students stu = (Students) session.get(Students.class, 1);
System.out.println(stu.getAddress());

 控制台显示的sql如下:

Hibernate: 
    select
        students0_.STUID as STUID1_1_0_,
        students0_.NAME as NAME2_1_0_,
        students0_.ADDRESS as ADDRESS3_1_0_,
        students0_.CLASSID as CLASSID4_1_0_ 
    from
        STUDENTS students0_ 
    where
        students0_.STUID=?
Hibernate: 
    select
        classes0_.CLASSID as CLASSID1_0_0_,
        classes0_.CLASSNAME as CLASSNAM2_0_0_ 
    from
        CLASSES classes0_ 
    where
        classes0_.CLASSID=?
wangzhe

 即我在只查询一个student的属性值时,它也将我的class表做了一个初始化,这种策略对于hibernate性能来说是很不好的。

懒加载问题:

    

Students stu = (Students) session.get(Students.class, 1);
System.out.println(stu.getAddress());
session.close(); //此处 session关闭
System.out.println(stu.getClasses().getClassName());

控制台sql:

    

Hibernate: 
    select
        students0_.STUID as STUID1_1_0_,
        students0_.NAME as NAME2_1_0_,
        students0_.ADDRESS as ADDRESS3_1_0_,
        students0_.CLASSID as CLASSID4_1_0_ 
    from
        STUDENTS students0_ 
    where
        students0_.STUID=?
Hibernate: 
    select
        classes0_.CLASSID as CLASSID1_0_0_,
        classes0_.CLASSNAME as CLASSNAM2_0_0_ 
    from
        CLASSES classes0_ 
    where
        classes0_.CLASSID=?
wangzhe
zhihuei

 由上可以看出:lazy=false 就是关闭掉了懒加载 ,所以这个是解决懒加载异常的策略之一,但是,这个策略却

极其消耗性能 。所以 我们一般在N的一方不去定义 lazy=false;顺便说一句 lazy="false"是没有懒加载异常的

单向N-1的检索策略:

               N-1  lazy ="proxy"(即单端N的一端默认的加载策略) 即生成代理 就是延时加载

代码如下:

         

	Students stu = (Students) session.get(Students.class, 1);
		System.out.println(stu.getAddress());

 控制台sql如下:

         

Hibernate: 
    select
        students0_.STUID as STUID1_1_0_,
        students0_.NAME as NAME2_1_0_,
        students0_.ADDRESS as ADDRESS3_1_0_,
        students0_.CLASSID as CLASSID4_1_0_ 
    from
        STUDENTS students0_ 
    where
        students0_.STUID=?
wangzhe

我们可以发现 .并没有初始化对应的classes 表 ,此时 classes对象的一个代理对象,

当session关闭时.代码如下:

Students stu = (Students) session.get(Students.class, 1);
		System.out.println(stu.getAddress());
		
		session.close(); //此处 session关闭
		System.out.println(stu.getClasses().getClassName());

会报一个懒加载异常  

懒加载异常解决办法如下:

典型应用:

          在hibernate 与spring整合时  有一张学生表与班级表 ,当我们要显示学生的的所有信息的时候用显示所有的班级名称,如果我们以默认的懒加载策略(lazy="proxy") 会报懒加载错误 ,因为此时班级对象是个代理(班级对象没有做初始化工作)而此时session却关闭了,所以会报 no -session........的懒加载异常。

那怎么解决呢?

                 有4种办法可以解决:

1.关闭懒加载(lazy=false)          就是 我在加载Student对象的时候就把classes对象的初始化工作完成,代码如上. 问题是这样极大的消耗我们的查询性能.所以不推荐 甚至这种办法应该舍弃掉。

2.在web.xml 里配置一个过滤器 ,即OpensessioninView 。    顾名思义 就是在渲染视图的时候session是一直开着的即当前事物方法结束之后 session 也一直开着 直到 视图渲染完成 。问题是,这会导致session混乱

在做高并发量小的项目时可以.但是高并发量就会导致不知预想的错误,所以 不推荐

3.改变抓取策略   我们在做本地sql的时候 会用到 left outer join  inner  jion等等一系列的连接查询

来查询出关联的表的数据 所有 我们可以在hql语句 定义一个left outer join 的连接查询

 代码如下:

FROM STUDENTS s LEFT OUTER JOIN FETCH s.classes;

也可以在N的一端的配置文件中指定抓取策略  即fetch="join"  但是我们一般不要在配置文件中去配置

 原因是 只要我们一查询 STUDENTS 表的属性时 它都会发出这样的左外连接语句.

4.在session关闭之前 就做一个初始化工作:

                如  Classes classes =Students的引用.getClasses();

                 但这个初始化工作视具体情况而定 .

                                                                      

单向多对一与双向多对一是一样的 。

单向1-N与双向1对多也是一样的 。只不过在单向或双向中 它的默认检索策略为 lazy="true"即开启懒加载。

猜你喜欢

转载自982699697.iteye.com/blog/2304448