本文出处:http://blog.csdn.net/chaijunkun/article/details/9083171,转载请注明。由于本人不定期会整理相关博文,会对相应内容作出完善。因此强烈建议在原始出处查看此文。

最近维护一个之前做的项目,项目采用的是Spring 3和Hibernate 4 JPA做的。由于当时做项目的时候经验偏少,又图省事,所以使用了Hibernate中的懒加载,所谓懒加载这里我多说两句(知道的朋友请无视这一段),数据库中表A和表B都分别映射了JPA的Pojo对象。从逻辑上说表A中的某个字段要和表B的主键进行连接操作(inner join,left join)可以不用手工去显式写JPQL语句,而可以通过注解的方式去映射,当需要取对应的值时直接调用.get方法即可,例如:

分别映射时:

表A(员工表):

import java.io.Serializable;import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;public class A implements Serializable{private static final long serialVersionUID = 8985074792763641465L;@Id@GeneratedValue@Column(name= "idx")private Integer idx;@Column(name="name", nullable= false)private String name;@Column(name="departId", nullable= false)private Integer departId;//getters and setters}

表B(部门表):

import java.io.Serializable;import javax.persistence.Column;
import javax.persistence.GeneratedValue;import javax.persistence.Id;public class B implements Serializable{private static final long serialVersionUID = 5994901985887071206L;@Id@GeneratedValue@Column(name="departId")private Integer departId;@Column(name="departName", nullable= false)private String departName;//getters and setters}

传统的查询方法中表A要想知道某个员工的部门名称,需要通过A.departId然后再查询B.departId=A.departId才能得知B.departName。所以在JPA中提供了一个更为方便的方法:

只需要对主表(表A)做下面是修改即可:

import java.io.Serializable;import javax.persistence.Column;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;public class A implements Serializable{private static final long serialVersionUID = -8453322980651820968L;@Id@GeneratedValue@Column(name= "idx")private Integer idx;@Column(name="name", nullable= false)private String name;@ManyToOne(fetch = FetchType.LAZY)@Column(name="departId", nullable= false)private B b;//getters and setters}

JPA标准中这种对象关联默认是全加载,即查询到A后根据映射关系会立即查询对应的B,并将其注入到结果A中。但是我们为了提高性能,会将映射方式改为懒加载(fetch= FetchType.LAZY),当结果A第一次调用getB()的时候才会去查询相应的B并将其注入。这就是懒加载

问题来了,框架并不知道我们什么时候会调用get方法去加载关联对象,项目中,我在Controller中查询出来的结果往往是A,剩下的现实逻辑交给了jsp,然而JSP中会使用${A.b.departName}这样的操作,一旦有这样的代码就会有如下提示:

org.hibernate.LazyInitializationException: could not initialize proxy - no Session

懒加载时在JSP处理时找不到底层的数据库连接会话,造成语句无法执行,后来通过查阅资料,得到了如下方法:

在JPA配置文件applicationContext-jpa.xml中加入如下的拦截器:

<!--实体管理器工厂Bean -->
<bean id="entityManagerFactory"   class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"><property name="persistenceUnitName" value="default" />
</bean>
<!-- 建立视图内拦截器来解决JPA中访问延迟加载属性时产生的无会话异常 -->
<!-- LazyInitializationException: could not initialize proxy no session -->
<!-- 此拦截器会注入到servlet配置中的DefaultAnnotationHandlerMapping中 -->
<bean name="openEntityManagerInViewInterceptor" class="org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor"><property name="entityManagerFactory"><ref bean="entityManagerFactory" /></property>
</bean>

然后将这个拦截器注入到基于注解的默认注解处理器配置中(spring-servlet.xml):

<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"><property name="interceptors"><list><ref bean="openEntityManagerInViewInterceptor" /></list></property>
</bean>

本来到这里懒加载已经配置成功了,在JSP中也可以使用。但后来加入了JSR 303,这个拦截器就失效了,又提示“org.hibernate.LazyInitializationException: could not initialize proxy - no Session”,经过比对,只是在spring-servlet.xml中增加了一行配置:

<mvc:annotation-driven />

这也是很多人说的最简单的开启JSR 303的配置方法。虽然JSR 303开启了,但是重要的懒加载却失效了,通过屏蔽该条注释,懒加载又能正常工作了,但JSR 303又失效了。这也印证了我的猜想。难道就没有鱼和熊掌兼得的方法吗?百度既然没找到答案,还是得靠谷歌啊。后来找到了一个遇到类似问题的求助帖:

http://stackoverflow.com/questions/3230633/how-to-register-handler-interceptors-with-spring-mvc-3-0

其中有人回答:

By default, Spring will register a BeanNameUrlHandlerMapping, and a DefaultAnnotationHandlerMapping, without any explicit config required.
默认地,spring会自动注册一个BeamNameUrlHandlerMapping和一个DefaultAnnotationHandlerMapping,没有要求任何进一步的配置

If you define your own HandlerMapping beans, then the default ones will not be registered, and you'll just get the explicitly declared ones.
如果你定义了自己的HandlerMapping,则默认的就不会被注册,你就能得到你所声明的HandlerMapping

So far, so good.

目前还不错,但是问题来了

The problem comes when you add <mvc:annotation-driven/> to the mix. This also declares its own DefaultAnnotationHandlerMapping, which replaces the defaults.

当加入了配置<mvc:annotation-driven />,spring仍然会声明自己的DefaultAnnotationHandlerMapping,并且替换默认的。

原来如此,怪不得之前的配置不起作用了。现在唯一的解决办法就是去掉这个配置,但是JSR 303怎么手动配置开启呢?

在这篇Spring官方文档中找到了答案

http://static.springsource.org/spring/docs/3.0.0.RC1/reference/html/ch05s07.html

<!-- Invokes Spring MVC @Controller methods -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"><property name="webBindingInitializer"><!-- Configures Spring MVC DataBinder instances --><bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer"><property name="validator" ref="validator" /></bean></property>
</bean><!-- Creates the JSR-303 Validator -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />

之前我的spring-servlet.xml配置文件中关于AnnotationMethodHandlerAdapter是按照默认初始化的:

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />

修改了之后懒加载和JSR 303可以共存了。

经验分享,希望对大家有所帮助。

让Spring 3中jsp的数据对象使用懒加载(FetchType.LAZY)与Controller的JSR 303并存相关推荐

  1. mysql 懒加载数据_jpa如何懒加载大字段,懒加载之后又如何获取懒加载字段

    前言:对于大字段,我们在查询列表的时候不需要查询,但是修改的时候有需要展示大字段内容,怎么办 问1.jpa如何懒加载大字段?即查询列表的时候不查询出来 问2.懒加载之后又如何获取懒加载字段.比如,在后 ...

  2. V3.0element中table表格树形结构与懒加载通过接口获取展开行数据,并实现自动展开某行以及展开行数据删除,编辑,新增,展开行某些列不显示等功能

    1.获取列表后自动展开第一行,以及列表序号的显示 需要展开哪行,就赋值 expandsId 某行id 值就行了 2.展开某行时通过接口获取子行数据,一般需求是通过父行的id,来获取他的子行数据--lo ...

  3. java中什么叫懒加载_java懒加载的原理

    聊一下以下名词.概念或用法:lazy.lazy="extra".inverse.fetch.fetch="join".fetch=" subselec ...

  4. 在ThinkPHP框架(5.0.24)下引入Ueditor并实现向七牛云对象存储上传图片同时将图片信息保存到MySQL数据库,同时实现lazyload懒加载...

    这是我花了很多天的时间才得以真正实现的一组需求. 文章后面有完整Demo的GitHub链接. 一. 需求描述 1. 应用是基于ThinkPHP5开发的: 2. 服务器环境是LNMP,PHP版本是7.2 ...

  5. Spring Bean懒加载与非懒加载

    懒加载:对象使用的时候才去创建.节省资源,但是不利于提前发现错误: 提前加载:容器启动时立马创建.消耗资源,但有利于提前发现错误 Spring 默认设置是非懒加载 1,由于在controller中会注 ...

  6. java懒加载注解_在springboot中实现个别bean懒加载的操作

    懒加载---就是我们在spring容器启动的是先不把所有的bean都加载到spring的容器中去,而是在当需要用的时候,才把这个对象实例化到容器中. @Lazy 在需要懒加载的bean上加上@Lazy ...

  7. mui ajax 懒加载,MUI框架运用中遇见问题总结

    H5在移动端的开发趋势化越来越大,相对App来说,H5优势有: 跨平台,兼容性强 开发速度快,成本较低 迭代周期短 技术成本低 但当我们在开始移动端的项目开发时,又愁着有什么样的好的UI框架能让我们减 ...

  8. 图片懒加载以及数据懒加载

    当一个单页面应用加载发送的请求很多时,页面可能会出来的很慢影响用户体验,此时我们就可以对项目进行优化,使用数据懒加载以及图片懒加载优化网络性能.懒加载的原理是当组件对象或者Dom对象出现在可视区域的时 ...

  9. Spring - bean的lazy-init属性(懒加载)

    默认情况下,容器初始化的时候便会把bean实例化,通常这样做可以让一些配置或者bean实例化的异常在容器启动的时候就发现,而不是在N久之后.但有时候,我们希望某个可能不会用到但又不是100%不用的be ...

最新文章

  1. 深入理解C语言的define
  2. Apache Thrift - java开发详解
  3. Chrome 调试 Android WebView 网页
  4. http请求头状态码
  5. if条件判断C语言,if条件判断语句,谁能帮我分析一下?
  6. Java Web 开发详解
  7. [Linux网络编程学习笔记]索引
  8. 史上最失败系统!微软正式终止对Vista支持
  9. 哈工大2019计算机专业录取分数线,哈尔滨工业大学2019年高考分省分专业录取分数线...
  10. 深入理解Android网络编程 技术详解与最佳实践电子书pdf下载
  11. python模拟鼠标拖动滑块_Python中selenium的作用链模拟滑块运动,python,ActionChains,移动...
  12. 各种文件的mime类型
  13. mysql模糊查询之索引优化
  14. oracle中删除表的四种基本操作 2021-11-03
  15. 斯坦福大学公开课机器学习:Neural Networks,representation: non-linear hypotheses(为什么需要做非线性分类器)...
  16. Golang 多版本管理神器 gvm
  17. windows10系统-10-VirtualBox中的四种网络连接方式
  18. 百度地图绘制实时路线以及最短线路规划
  19. Python进行假设检验
  20. 土木类专业毕业设计全流程讲解,看完再也不担心毕业~

热门文章

  1. 解读Linux下的password命令
  2. 少撸两局教你搭个博客玩
  3. 使用bind构建本地简易dns服务器
  4. Linux下套接字详解(四)----简单的TCP套接字应用(迭代型)
  5. 我与小娜(04):时空变换,亦真亦幻
  6. POJ 2553 The Bottom of a Graph
  7. Java网络编程从入门到精通(25):创建ServerSocket对象
  8. 下班前网上搜集的方法哈哈
  9. 初探 Go 的编译命令执行过程
  10. 1145: 零起点学算法52——数组中删数II