工作中源代码学习

SpringDataJPA + Hibernate @ManyT

2018-05-31  本文已影响31人  ___TheOne___

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
}
上一篇 下一篇

猜你喜欢

热点阅读