本文出处: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
}
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)做下面是修改即可:
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
}
问题来了,框架并不知道我们什么时候会调用get方法去加载关联对象,项目中,我在Controller中查询出来的结果往往是A,剩下的现实逻辑交给了jsp,然而JSP中会使用${A.b.departName}这样的操作,一旦有这样的代码就会有如下提示:
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
懒加载时在JSP处理时找不到底层的数据库连接会话,造成语句无法执行,后来通过查阅资料,得到了如下方法:
在JPA配置文件applicationContext-jpa.xml中加入如下的拦截器:
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
当加入了配置
原来如此,怪不得之前的配置不起作用了。现在唯一的解决办法就是去掉这个配置,但是JSR 303怎么手动配置开启呢?
在这篇Spring官方文档中找到了答案
http://static.springsource.org/spring/docs/3.0.0.RC1/reference/html/ch05s07.html
之前我的spring-servlet.xml配置文件中关于AnnotationMethodHandlerAdapter是按照默认初始化的:
修改了之后懒加载和JSR 303可以共存了。
经验分享,希望对大家有所帮助。