zoukankan      html  css  js  c++  java
  • ssh中Hibernate懒加载,session问题的学习与理解

     

    交代本项目中要求获取session的方式如下:

     public Session getCurrentSession() {
            // 增删改使用的session,事务必须是开启的(Required,即propagation="REQUIRED"),否则获取不到
            return sessionFactory.getCurrentSession();
        }
    
        public Session getQueryCurrentSession() {
            // 查询使用的session,,该生成的session没有事务。
            return sessionFactory.openSession();
        }

    问题1描述:

      Component对Arch为多对多的关系,小明在页面需要展示Component的记录,然后展示出来有一条记录a是重复的,经过一番排查,发现记录a在中间表中对应着两条

    记录b,c。即因为Component与Arch是多对多的关系,故在中间表中有两条a对应着不同的b,c。那为什么仅仅只是查询Component,页面会显示两条重复的a记录呢?原

    来,本次项目中关闭了懒加载,开启了立即加载,并且小明在查询Component的时候使用的QBC查询。

    1.什么是懒加载(延迟加载)?什么是立即加载?

      当数据在需要用到的时候才去获取就是懒加载;不管数据用不用到一次性全部查询获取出来。由此可见立即加载会造成资源浪费,并且导致查询效率低下。

    2.什么是QBC查询

      QBC,即Query By Criteria,是Hibernate提供的一种查询方式,不需要写hql语句,直接使用方法实现,省略QBC的使用方法与步骤,通过如下配置让其在控制台打印

    出对应的sql语句,来进行观察。

    <prop key="hibernate.show_sql">true</prop>
    
    <prop key="hibernate.format_sql">true</prop>

      可以从控制台打印的一些sql语句,看出只要在实体类中配置了关联关系在进行QBC查询的时候,都会进行left outer join左外连接查询,a a  aa a a ,好奇害死猫呀,这

    就又让我去看看普通的hql语句是不是这样做的呢?果然不同。。。真的是,QBC与HQL两种查询的区别,大致在于QBC查询,只要在实体类中配置了关联关系在进行查

    询的时候,都会进行left outer join左外连接查询,而hql查询是根据表字段来进行查询的并没有进行表关联查询,所以有可能就算你使用了立即加载,在查询的时候也不会

    出现有重复记录的bug,a a a a  a,也就不会有现在这一大堆的思考了。。不过这样也是很好很好的,让我又明白了并学习了当初并不懂的一些知识。。啊哈哈哈。。。。

      回到上面的问题,重复记录的原因:因为使用了立即加载模式,查询的时候,多对多关联关系的Arch表进行了中间表的关联 进行了左外连接查询 故出现了2条重复的记录a

    解决记录重复问题:

    1.采用立即加载,在查询的时候,添加去重distinct

    criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

    2.关闭立即加载,使用懒加载(延迟加载),这样在查询Component的时候就不会进行中间表的左外连接查询,也就不会有重复记录

    问题2描述:

      使用方法1,跟使用方法2都可以解决问题,但是,使用方法2,现在又出了问题。使用方法2,可以解决小明重复的问题,但是凤姐又出问题了,由于凤姐通过

    Component的id查询到的Component,是在dao层使用的openSession()获取的Session,即在dao层中就已经将session关闭了,现在又使用了懒加载,故凤姐在action

    层无法通过Component对象来get到对应的Arch集合,这个时候会抛no session的异常。说完,要是跟我一样是小白新手的话,可能是懵比的,那就再简单介绍下本

    此项目中所涉及到的知识:(也是折腾了一两天,才对其中的知识懵懵懂懂!!!!!!!!,只是个人表面肤浅的理解。。。。)

    3.获取session的两种方式?

    1.openSession(),直接打开一个新的session。需要自己手动去关闭。

    2.getCurrentSession(),获取当前session,当session不存在,就新打开一个,否则获取已经有的session。不需要自己手动关闭,交由spring管理,当service层的事务被

    提交完成后,session会自动关闭。

    4.为什么要配置增删改获取的session,要在service层自动关闭?

      了解以下hibernate事务提交过程就会知道了:

    .....
    
    Session session=sf.openSession();
    
    Transaction tx=session.beginTransaction();
    .....
    
    tx.commit();
    
    s.close();

      1.创建session实例

      2.用session创建Transaction实例,开始一个事务。

      3.利用session方法进行持久化操作。将实体对象的持久化到数据库中。

      4.提交操作结果,结束事务。对实体对象的持久化操作结束后,必须提交事务。

      5.关闭session,与数据库断开连接

    知道了事务提交的过程,也就明白了为什么本次项目会要求增删改操作使用getCurrentSession(),查询操作使用openSession()。因为增删改要有事务的操作,而事务是作

    用在service业务层的,并且是事务提交之后,session才能关闭。故不能在dao层立即关闭session,故不用openSession()。因为查询不需要事务,故使用openSession(),

    也就不需要在查询的时候开启事务了,以免造成资源的浪费,就可以直接在dao层关闭session,对事务不造成影响。但是但是但是,问题来了,这就要求我们只能使用立

    即加载,而不能使用延迟加载了,因为涉及到查询的操作,都是在dao层关闭了了session,在service层或表现层根本不能根据对象去获取多对多关系的集合属性,因为

    session已经在dao层就关闭了。

      所以绕来绕去,解决本次项目问题的方法,还是只能采用立即加载.

      对于只能使用立即加载,当数据多了以后,这也会造成效率低的情况,所以最好建议不要这么做,但是这也是没有办法的事,毕竟现在本项目要求查询用的是

    openSession(),并立即关闭。但是如果抛开本次项目,该如何解决懒加载的问题呢?如何做到使用懒加载而不抛异常呢?

      个人认为只能更改本次项目中,查询操作 获取session的方式,将openSession()也换为getCurrentSession(),虽然现在查询也需要加上事务了(事务必须是开启的,即

    propagation="REQUIRED",否则通过getCurrentSession()是获取不到session的。),但是我也不知道,这个立即加载造成的效率跟查询开启事务,来比较,谁比较浪费资

    源????????下面就说下,当查询操作的session变为getCurrentSession()后,如何解决懒加载问题。

    再次声明此方法前提:在dao层以getCurrentSession()获取session来查询对象,这个时候dao层不会立即关闭sesion,交由spring来管理,在service层,当事务提交完成后,session会自动关闭。

    项目中涉及到懒加载的位置,一般如下

    1..在业务层service中,需要使用懒加载

      这个时候session还没有关闭,就随便用啦

    2.在表现层action中,需要使用懒加载

      由于现在session,已经被关闭,所以在表现层中再用对象去获取多对多关系的集合属性,是会抛懒加载no session异常的。那么,如何解决?

    解决懒加载(延迟加载获取不到对象的关联属性值)问题:  

      1.在session关闭前,即在业务层中 将要获取的数据强行进行初始化,即初始化需要用到的集合属性,这样在表现层action中就再次获取的时候就是可以的,这里的

    强行有很多种方法的,我就说下我用到的方法吧:

     

      2.延长session的生命周期,让其在一次响应后结束(quest,response)后,才被关闭。

        具体做法:在web.xml中配置

    <!-- 
            延长session的生命周期:
            关联关系 需要加载的时候就去查找 不需要用到的时候就不查找
            比如:加载部门名字 这个时候em.dm.name会用到关联关系
         -->
        <filter>
               <filter-name>openSessionInView</filter-name>
               <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
        </filter>
        
        <filter-mapping>
            <filter-name>openSessionInView</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>

     

    ===============================================================

    真的是整理的好累好累,虽然还是不咋地,但是就这样吧。啊啊啊啊啊。。。。。。。。。。。。。。。。

     思考花絮:

    1.凤姐现在在Component模块中需要用到对应的Arch对象

    实现方法:通过Component的id获取到Component后,通过Component对象来get到对应的Arch集合

    由于在service层通过id获取到Component采用OpenSesssion()打开session 要在service层手动关闭session

    故当在action表现层就获取不到对应的Arch集合,因为此时是延迟加载模式,然后session又已经被关闭了

    如何解决?

    方法1:采用立即加载模式

    方法2:采用延迟加载模式,在service层通过getCurrentSession()方式获取session,此中方式会在事务完成后

    (本查询结束离开service层)自动进行提交,然后在web.xml里面配置spring的openSessionInView,来延长session的

    生命周期,让其不自动在离开service层就关闭,而是让session在一次请求响应(request,response)结束后才进行自动关闭,

    即加上这个配置后,在session在action表现层也是可以作用的。此时就可以在变现曾拿到对应的Arch对象

    1.session

    如何获取session?两种方式

    两种方式的区别

    2.懒加载

    何为懒加载?懒加载有什么作用?

    如何解决项目中懒加载问题?

    立即加载与懒加载如何选择?

    使用立即加载带来的问题?

    比如使用hql查询与qbc查询的区别 而带来的异常

    hql查询不使用关联关系查询  直接利用表字段什么的

    qbc查询使用hibernate.format_sql在控制台打印数据库查询语句  可以观察到 只要配置了关联关系

      就会发出左外连接查询left join

    因此 使用qbc查询 当存在多对多的关系时,开启了立即加载的模式,此时,查询 会出现一条记录重复的现象 

    解决办法:1.去重 distinct

         2.使用延迟加载

    那么问题来了  对于在action表现层 如何使用延迟加载  需要使用spring来延长session的生命周期(request,response结束后才关闭session)或者使用getCurrentSession()来获取session,并在session关闭前,将要使用的数据进行初始化获取

    对于小白,对,没错,说的就是我这样的, 啊哈哈哈哈。。。一些业务方法 会喜欢写在表现层 最好的是 把一些处理业务逻辑的方法  写在业务层  这样 也就不用延长session的生命周期了  真的是

  • 相关阅读:
    java反射机制
    java的hashmap与hashtable说明,简单易理解
    awk
    python的w+到底是什么
    hive深入浅出
    【OpenCV新手教程之十五】水漫金山:OpenCV漫水填充算法(Floodfill)
    对你相同重要的非技术贴,10件事证明你跟错了人
    SVM中为何间隔边界的值为正负1
    pushlet服务端推送——多播
    谁洗碗,搭载我的技术目标,起航。
  • 原文地址:https://www.cnblogs.com/eleven258/p/8000873.html
Copyright © 2011-2022 走看看