为了账号安全,请及时绑定邮箱和手机立即绑定

spring-data-jpa多对多双向关联,查询的时候进入死循环

spring-data-jpa多对多双向关联,查询的时候进入死循环

qq__4787 2017-10-20 00:11:48
两个实体类User@Data @Entity @Table(name = "sys_user") public class User {     @Id     @GeneratedValue     @Column(name = "user_id")     private Integer userId;     @Column(name = "username")     private String username;     @ManyToMany(cascade = {CascadeType.ALL}, fetch = FetchType.LAZY)     @JoinTable(             name = "user_role",             joinColumns = {@JoinColumn(name = "user_id")},             inverseJoinColumns = {@JoinColumn(name = "role_id")}     )     private Set<Role> roles; }Role@Data @Entity @Table(name = "sys_role") public class Role {     @Id     @Column(name = "role_id")     private Integer roleId;     @Column(name = "role_name", unique = true)     private String roleName;     @ManyToMany(cascade = {CascadeType.ALL}, fetch = FetchType.LAZY, mappedBy = "roles")     private Set<User> users;测试代码@Transactional     @Test     public void save() throws Exception{         Set<Role>roles = new HashSet<Role>();         roles.add(new Role(1, "USER"));         roles.add(new Role(2, "ADMIN"));         repository.save(new User("张三", roles));     }     @Transactional     @Test     public void findAll(){         List<User> users = repository.findAll();         for (User user : users) {             System.out.println(user);         }     }在使用插入数据的时候没有任何问题,但是当查询的时候报错org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: wang.xiaoqiang.manytomany.entity.User.roles, could not initialize proxy - no Session这个可以理解,懒加载的时候丢失了session无法获取roles信息,当将user中的集合设置为急加载模式,结果就遇到StackOverflowError哪位大佬有相关经历,帮帮忙。。。
查看完整描述

1 回答

已采纳
?
特南克斯

TA贡献14条经验 获得超9个赞

首先你要理解这是双向关联,双向关联中你如果从数据库里面查询一个User对象,那么User对象里面有Role,Role里面又有User对象,那么你用syso输出User对象,如果toString方法里面包含有输出User.roles的话,那么是必然会造成死循环的。如果你用sping mvc等框架将后台数据返回给前台也是同理,也会造成返回的JSON数据死循环

那么要如何解决?

解决办法就是在序列化实例的时候中断循环就好。首先你要理解这不是spring-data-jpa的问题,这是一个序列化的问题。

例如如果是用jsckson对数据进行序列化的的话,可以使用下面的注解。

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@Data
@Entity
@Table(name = "sys_user")
public class User {
    @Id
    @GeneratedValue
    @Column(name = "user_id")
    private Integer userId;
    @Column(name = "username")
    private String username;
    @JsonIgnoreProperties(value = { "users" })
    @ManyToMany(cascade = {CascadeType.ALL}, fetch = FetchType.LAZY)
    @JoinTable(
            name = "user_role",
            joinColumns = {@JoinColumn(name = "user_id")},
            inverseJoinColumns = {@JoinColumn(name = "role_id")}
    )
    private Set<Role> roles;
}

这样的话,你再序列化User对象时,

user.roles 这个对象中只有 user.roles[i].id 和  users.roles[i].name 而没有 user.roles.users!!!!

ok,问题解决!!!


查看完整回答
3 反对 回复 2017-11-01
  • qq__4787
    qq__4787
    非常感谢!原来一直是因为toString()方法中循环调用引发的问题,之前我也尝试着将重写toString()方法,避免循环调用。结果发现并没有效果,原来是使用lombok中的@Data注解后会覆盖掉原来的toString()方法,导致自定义的toString()方法并未生效。看来以后测试中也的看情况的使用toString()方法了。。。
  • 特南克斯
    特南克斯
    这个问题也困扰了我一段时间,但是到现在我也没有完美的解决方法。 我见过一些API后台是关联深度是可以控制的,类似relation_depth = 0 返回数据不包含子对象,也就是没有user.roles。relation_depth = 1 返回数据有user.roles。但是没有user.roles.users。还可以更深。因为复杂的数据库表结构可能不仅仅是一层的多对多。 但是绝大多数的情况下关联深度为1,一般都可以用了。 至于toString,你只要注意下,不要对象循环输出,就不是内存溢出了,也是可以用的
  • qq_白天不懂爷的黑_2
    qq_白天不懂爷的黑_2
    请问onetoone怎么解决死循环的问题呢?
点击展开后面3
  • 1 回答
  • 0 关注
  • 9956 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信