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的生命周期了 真的是
ssh中Hibernate懒加载,session问题的学习与理解的更多相关文章
- 解决hibernate中的懒加载(延迟加载)问题
解决hibernate中的懒加载(延迟加载)问题 我们在开发的时候经常会遇到延迟加载问题,在实体映射时,多对一和多对多中,多的一样的属性默认是lazy="true"(即,默认是 ...
- Hibernate的懒加载session丢失解决方法
在web.xml加入spring提供的过滤器,延长session的生命周期 <!--Hibernate的懒加载session丢失解决方法 --> <filter> <fi ...
- hibernate懒加载(转载)
http://blog.csdn.net/sanjy523892105/article/details/7071139 懒加载详解 懒加载为Hibernate中比较常用的特性之一,下面我们详细来了解下 ...
- Hibernate懒加载解析
Hibernate懒加载解析 在Hibernate框架中,当我们要访问的数据量过大时,明显用缓存不太合适, 因为内存容量有限 ,为了减少并发量,减少系统资源的消耗,这时Hibernate用懒加载机制来 ...
- hibernate懒加载
Hibernate懒加载解析 hibernatejoinsession数据库sqlobject Hibernate懒加载解析 在Hibernate框架中,当我们要访问的数据量过大时,明显用缓存不太合适 ...
- 关于Hibernate懒加载问题的最终解决方案
看到一篇Hibernate懒加载的文章,所以转载,原地址如下: http://tuoxie007.iteye.com/blog/334853 Hibernate的强大之处之一是懒加载功能,可以有效的降 ...
- Hibernate懒加载深入分析
Hibernate懒加载深入分析 懒加载可以提高性能吗? 不可以简单的说"能",因为Hibernate的关系映射拖累了SQL的性能,所以想出懒加载来弥补.只是弥补而以,不会超越. ...
- 关于s2sh框架关于hibernate懒加载问题的说明和解决方案
首先我们来看下面这个图,解释了一个web程序的一次请求流程! 懒加载异常的说明: 懒加载就是我们在查询一个对象时,它所有的属性是否要被查出来! 如果懒加载开启的话,session在service层就被 ...
- Hibernate懒加载的三种解决方案
Hibernate懒加载的两种解决方案: 1.Hibernate.initialize(代理对象) 2.在*.hbm.xml映射文件中添加lazy="false"属性 3.使用op ...
随机推荐
- onclick事件触发 input type=“file” 上传文件
添加按钮: <input type="button" name="button" value="浏览" onclick="j ...
- maven基本基础知识及命令学习-1
Maven概述:Maven是很有效的项目管理工具,maven是基于项目对象模型(POM),可以通过一小段描述信息来管理项目构建.报告和文档的软件项目管理工具.统一管理环境,架包等. 一 maven下载 ...
- (转)Spark JAVA RDD API
对API的解释: 1.1 transform l map(func):对调用map的RDD数据集中的每个element都使用func,然后返回一个新的RDD,这个返回的数据集是分布式的数据集 l ...
- Leetcode题解(30)
98. Validate Binary Search Tree 题目 分析:BST按照中序遍历之后所得到的序列是一个递增序列,因此可以按照这个思路,先中序遍历,保存好遍历的结果,然后在遍历一遍这个序列 ...
- 最长上升子序列(NlogN)总结
最长上升子序列总结 最开始的知道最长上升子序列的时候,简单DP的时候,但是后来遇到很多最长上升子序列的问题就没法用DP来解决,时间复杂度和空间复杂度都不允许.
- HDU 4325 Flowers(树状数组)
Flowers Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Sub ...
- [译]ASP.NET Core 2.0 部分视图
问题 如何在ASP.NET Core 2.0中使用部分视图来重用页面的公共部分? 答案 新建一个空项目,在Startup中添加MVC服务和中间件: public void ConfigureServi ...
- HTML5 input事件检测输入框变化[转载]
原文:http://www.linuxidc.com/Linux/2015-07/119984.htm 之前一直用change事件来监听输入框内容是否发生变化,只有当输入框失去焦点时才会触发,没想到h ...
- URI 方法 encodeURI() encodeURIComponent() docodeURI() decodeURIComponent()
URI 方法 encodeURI() encodeURIComponent() docodeURI() decodeURIComponent() var sUri = “http://ww ...
- VMware系统克隆
第1章 搭建VMware实战环境 1.1 vmware主机配置-网络配置 1.1.1 虚拟主机添加网卡信息(5) a.右键虚拟主机→设置→添加虚拟网卡硬件设备 b.设置网络适配器类型→完成添加 1.1 ...