SpringDataJPA + Hibernate @ManyT
Part1.单边设置多对多且延时加载,No Session问题
1.场景
项目中涉及到两个数据库Entity实体:终端用户TerminalUser 和 网点Merchants。两者之间的关系是多对多:一个终端用户可以管理多个网点,一个网点可以被多个终端用户管理。
如果终端用户的角色是:业务员和管理员,直接通过@ManyToMany级联出管理网点列表即可。但是如果终端用户是出单员,需要查询其所属网点,设置到TerminalUser中。
2.结论:
1>@ManyToMany只设置在了终端用户TerminalUser这边,Merchants不设置多对多标签,便不会出现递归的情况;
@Entity
public class Course {
private String cId;
private String cName;
private String cRemark;
private Integer cGrade;
private Date cTime;
private Date uTime;
//选修课程的同学信息---begin
private List<Student> studentList = new ArrayList<Student>();
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "STU_COURSE",
joinColumns = { @JoinColumn(name = "C_ID") },
inverseJoinColumns = { @JoinColumn(name = "STU_ID") })
public List<Student> getStudentList() {
return studentList;
}
public void setStudentList(List<Student> studentList) {
this.studentList = studentList;
}
//选修课程的同学信息---end
2>使用实体TerminalUser 或者 生成一个TerminalUserDto;
3>查询出单员的所属网点:Merchants实体,Merchants必须纯净,没有其他属性设置延时级联(Lazy)标签;
否则最终使用@ResponseBody响应会报No session异常:
failed to lazily initialize a collection of role: org.jaden.jpa.entity.Course.studentList, could not initialize proxy - no Session
4>在实体TerminalUser或者TerminalUserVo上--->设置出单员所属网点Merchants即可。
展示结果:
{
"cGrade": 80,
"cId": "1703",
"cName": "现代钻石应用",
"cRemark": "钻石应用到工业生产中",
"cTime": 1499250325000,
"studentList": [{
"cTime": 1499250505000,
"className": "计科1201",
"gender": 1,
"stuId": "105",
"stuName": "靳浩东",
"uTime": 1499250508000
}],
"uTime": 1499250327000
}
Part2.双边设置多对多且延时加载,No Session问题
1.问题:在Course和Student实体两边均设置了多对多标签:@ManyToMany(fetch = FetchType.LAZY),但是当@ResponseBody响应时报No session问题。
Request processing failed; nested exception is org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: org.jaden.jpa.entity.Student.courseList, could not initialize proxy - no Session
导致问题原因:由于设置了延时加载,当@ResponseBody返回时,通过get方法获取Student.courseList时,session已经关闭了,所以不能获取到对应信息。
2.解决方案:
1>设置标签的延时加载为立即加载:
@ManyToMany(fetch = FetchType.EAGER)
2>在persistence.xml配置: 使得没有事务也可以获取懒加载的实体信息
<prop key="hibernate.enable_lazy_load_no_trans">true</prop>
3>在项目web.xml中添加如下过滤器:让session的存活周期延长到页面关闭
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>
org.springframework.orm.hibernate4.support.OpenSessionInViewFilter
</filter-class>
<init-param>
<param-name>sessionFactoryBeanName</param-name>
<param-value>mySessionFactory</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Part3.JSON递归级联问题
1>使用@JsonManagedReference 和 @JsonBackReference标签来解决。
引用地址 Infinite Recursion with Jackson JSON and Hibernate JPA issue
Course.java
@ManyToMany( mappedBy = "courseList", fetch = FetchType.EAGER)
@JsonBackReference
public List<Student> getStudentList() {
return studentList;
}
Student.java
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "STU_COURSE",
joinColumns = { @JoinColumn(name = "STU_ID") },
inverseJoinColumns = { @JoinColumn(name = "C_ID") })
@JsonManagedReference
public List<Course> getCourseList() {
return courseList;
}
递归的错误结果:
{"cId":"1701","cName":"商务礼仪","cRemark":"介绍商务相关的礼仪规则","cGrade":100,"cTime":1499250289000,"uTime":1499250291000,"studentList":[{"stuId":"104","stuName":"jaden","gender":1,"className":"靳浩东","cTime":1499250236000,"uTime":1499250238000,"courseList":[{"cId":"1701","cName":"商务礼仪","cRemark":"介绍商务相关的礼仪规则","cGrade":100,"cTime":1499250289000,"uTime":1499250291000,"studentList":[{"stuId":"104","stuName":"jaden","gender":1,"className":"靳浩东","cTime":1499250236000,"uTime":1499250238000,"courseList":[{"cId":"1701","cName":"商务礼仪","cRemark":"介绍商务相关的礼仪规则","cGrade":100,"cTime":1499250289000,"uTime":1499250291000,"studentList":[{"stuId":"104","stuName":"jaden","gender":1,"className":"靳浩东","cTime":1499250236000,"uTime":1499250238000,"courseList":[{"cId":"1701","cName":"商务礼仪","cRemark":"介绍商务相关的礼仪规
最终响应结果为:
{
"cGrade": 100,
"cId": "1701",
"cName": "商务礼仪",
"cRemark": "介绍商务相关的礼仪规则",
"cTime": 1499250289000,
"studentList": [{
"cTime": 1499250236000,
"className": "靳浩东",
"courseList": [{
"$ref": "$"
}, {
"cGrade": 80,
"cId": "1702",
"cName": "太极养生",
"cRemark": "介绍中国传统的知识,太极",
"cTime": 1499250325000,
"studentList": [{
"$ref": "$.studentList[0]"
}, {
"cTime": 1499250505000,
"className": "计科1201",
"courseList": [{
"$ref": "$"
}, {
"$ref": "$.studentList[0].courseList[1]"
}],
"gender": 1,
"stuId": "105",
"stuName": "靳浩东",
"teacher": {
"studentList": [{
"$ref": "$.studentList[0]"
},
{
"$ref": "$.studentList[0].courseList[1].studentList[1]"
}
],
"tAge": 34,
"tGender": 1,
"tId": "666",
"tName": "李创军",
"tSubject": "语文,政治"
},
"uTime": 1499250508000
}],
"uTime": 1499250327000
}],
"gender": 1,
"stuId": "104",
"stuName": "jaden",
"teacher": {
"$ref": "$.studentList[0].courseList[1].studentList[1].teacher"
},
"uTime": 1499250238000
}, {
"$ref": "$.studentList[0].courseList[1].studentList[1]"
}],
"uTime": 1499250291000
}