hibernate无限递归问题

项目异常如下:

2018-01-26 17:12:38.162  WARN 3128 --- [nio-8080-exec-6] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to write HTTP message: org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Infinite recursion (StackOverflowError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: demo.server.core.domain.User["userAddresses"]->
org.hibernate.collection.internal.PersistentBag[0]->
demo.server.core.domain.UserAddress["user"]->
demo.server.core.domain.User["userAddresses"]->
org.hibernate.collection.internal.PersistentBag[0]->
demo.server.core.domain.UserAddress["user"]->
......//无限递归



java.lang.StackOverflowError: null
    at java.lang.ClassLoader.defineClass1(Native Method) ~[na:1.8.0_111]
    at java.lang.ClassLoader.defineClass(Unknown Source) ~[na:1.8.0_111]
    at java.security.SecureClassLoader.defineClass(Unknown Source) ~[na:1.8.0_111]
    at java.net.URLClassLoader.defineClass(Unknown Source) ~[na:1.8.0_111]
    at java.net.URLClassLoader.access$100(Unknown Source) ~[na:1.8.0_111]
    at java.net.URLClassLoader$1.run(Unknown Source) ~[na:1.8.0_111]
    at java.net.URLClassLoader$1.run(Unknown Source) ~[na:1.8.0_111]
    at java.security.AccessController.doPrivileged(Native Method) ~[na:1.8.0_111]
    at java.net.URLClassLoader.findClass(Unknown Source) ~[na:1.8.0_111]
    at java.lang.ClassLoader.loadClass(Unknown Source) ~[na:1.8.0_111]
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source) ~[na:1.8.0_111]
    at java.lang.ClassLoader.loadClass(Unknown Source) ~[na:1.8.0_111]
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:709) ~[jackson-databind-2.8.1.jar:2.8.1]
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155) ~[jackson-databind-2.8.1.jar:2.8.1]
    at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:149) ~[jackson-databind-2.8.1.jar:2.8.1]
    at
...

看异常的名字会发现是栈溢出,而且第一处后面出现大量的递归的提示,这边的原因是因为使用了jpa的实体类注解@ManyToMany,@ManyToOne,@OneToOne并且是双向表关联

举个例子:

@Entity
@Table(name = "t_student")
public class Student{
    @Id
    @GeneratedValue
    private Integer sId;
    @Column(length = 20)
    private String sName;
    //学生所修课程
    @ManyToMany(mappedBy = "students")
    private List<Course> courses;
    //get、set 方法省略
}
@Entity
@Table(name = "t_course")
public class Course{
    @Id
    @GeneratedValue
    private Integer cId;
    @Column(length = 20)
    private String cName;
    //上课的学生
    @ManyToMany(cascade = CascadeType.ALL)
    private List<Student> students;
    //get、set 方法省略
}

一个student类和一个course类分别对应 t_student 表和 t_course表,它们是多对多的关系,一个学生可以修多个课程,一个课程可以有多个学生修

省略仓储层代码…

控制层代码

@RestController
public class TestController{
    @Autowired
    private StudentRepository studentRep;

    @RequestMapping("/test")
    public int test(){
        List<Student> students = stntRep.findAll();
        students.forEach(data->{
            System.out.println(data);
        });
        return 1;
    }
}

此时,程序运行便会报 java.lang.StackOverflowError: null 异常

java.lang.StackOverflowError: null
    at java.util.AbstractCollection.toString(Unknown Source) ~[na:1.8.0_111]
    at org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:510) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at java.lang.String.valueOf(Unknown Source) ~[na:1.8.0_111]
    at java.lang.StringBuilder.append(Unknown Source) ~[na:1.8.0_111]
    at com.demo.domain.Course.toString(Course.java:38) ~[classes/:na]
    at java.lang.String.valueOf(Unknown Source) ~[na:1.8.0_111]
    at java.lang.StringBuilder.append(Unknown Source) ~[na:1.8.0_111]
    at java.util.AbstractCollection.toString(Unknown Source) ~[na:1.8.0_111]
    at org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:510) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at java.lang.String.valueOf(Unknown Source) ~[na:1.8.0_111]
    at java.lang.StringBuilder.append(Unknown Source) ~[na:1.8.0_111]
    at com.demo.domain.Student.toString(Student.java:40) ~[classes/:na]
    ....

Student类中有一个字段List<Course> courses,在遍历集合中,输出一个student实例的时候,List<Course> courses 字段也将输出,因为是双向多对多的关联查询,每一个Course实例也会输出List<Student> students 字段值,因此一直递归下去直到栈溢出报错,若是单向多对多就不会发生这样地递归

其实一开始报这个错完全是因为对spring-data-jpa不熟悉,了解之后一想就通了。

解决办法:

方法一:
此处,若不需要查看关联表中的字段信息时,可以在遍历List<Student> students集合时先将关联对象设置为null,即:

students.forEach(data->{
    data.setCourses(null);
    System.out.println(data);
});

这样才能打印出Student 实例中除了courses 字段之外地所有数据

方法二:
取消使用双向多对多关联,改为使用单向多对多,这样也可以同时将关联表中所对应的数据查询出来使用

原文地址:https://blog.csdn.net/pbhLOVEpp/article/details/77945651

转载于:https://www.cnblogs.com/jpfss/p/11057046.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值