spring-data-jpa一对多、多对多双向关联,查询操作的时候进入死循环问题

此处以多对多为例,解决查询时进入死循环问题

1.用户实体类

@Entity
@Table(name = "t_sys_user")
@Data
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String password;
    private String fullName;
    private String email;
    
    @ManyToMany(cascade = CascadeType.REMOVE)
    @JoinTable(name = "t_sys_user_roles")
    private List<Role> roles;
}

2.角色实体类

@Entity
@Table(name = "t_sys_role")
@Data
public class Role {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    @Lob
    private String remark;

    @ManyToMany(cascade = CascadeType.REMOVE, mappedBy = "roles")
    private List<User> users;   //被维护端

}

在使用插入数据的时候没有任何问题,但是当查询的时候报错

java.lang.IllegalStateException: Cannot call sendError() after the response has been committed
	at org.apache.catalina.connector.ResponseFacade.sendError(ResponseFacade.java:472) ~[tomcat-embed-core-9.0.22.jar:9.0.22]
	at javax.servlet.http.HttpServletResponseWrapper.sendError(HttpServletResponseWrapper.java:129) ~[tomcat-embed-core-9.0.22.jar:9.0.22]
	at javax.servlet.http.HttpServletResponseWrapper.sendError(HttpServletResponseWrapper.java:129) ~[tomcat-embed-core-9.0.22.jar:9.0.22]
	...
	
java.lang.StackOverflowError: null
	at java.lang.ClassLoader.defineClass1(Native Method) ~[na:1.8.0_131]
	at java.lang.ClassLoader.defineClass(ClassLoader.java:763) ~[na:1.8.0_131]
	at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) ~[na:1.8.0_131]
	at java.net.URLClassLoader.defineClass(URLClassLoader.java:467) ~[na:1.8.0_131]
	at java.net.URLClassLoader.access$100(URLClassLoader.java:73) ~[na:1.8.0_131]
	at java.net.URLClassLoader$1.run(URLClassLoader.java:368) ~[na:1.8.0_131]
	at java.net.URLClassLoader$1.run(URLClassLoader.java:362) ~[na:1.8.0_131]
	at java.security.AccessController.doPrivileged(Native Method) ~[na:1.8.0_131]
	at java.net.URLClassLoader.findClass(URLClassLoader.java:361) ~[na:1.8.0_131]
	at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_131]
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335) ~[na:1.8.0_131]
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_131]
	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:737) ~[jackson-databind-2.9.9.jar:2.9.9]
	at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155) ~[jackson-databind-2.9.9.jar:2.9.9]
	at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:145) ~[jackson-databind-2.9.9.jar:2.9.9]
	at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:107) ~[jackson-databind-2.9.9.jar:2.9.9]
	at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:25) ~[jackson-databind-2.9.9.jar:2.9.9]
	at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:727) ~[jackson-databind-2.9.9.jar:2.9.9]
	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719) ~[jackson-databind-2.9.9.jar:2.9.9]
	at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155) ~[jackson-databind-2.9.9.jar:2.9.9]
	at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:145) ~[jackson-databind-2.9.9.jar:2.9.9]
	at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:107) ~[jackson-databind-2.9.9.jar:2.9.9]
	at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:25) ~[jackson-databind-2.9.9.jar:2.9.9]
	at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:727) ~[jackson-databind-2.9.9.jar:2.9.9]
	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719) ~[jackson-databind-2.9.9.jar:2.9.9]
	...

返回的数据

[{"id":1,"username":"admin","password":"$2a$10$.UblZbe8b/ESRiXrajVgo.HuhbJUezsPgpyD.tVrJraFmegiup.aS","fullName":"管理员","email":"[email protected]","roles":[{"id":1,"name":"管理员","remark":"系统管理员","users":[{"id":1,"username":"admin","password":"$2a$10$.UblZbe8b/ESRiXrajVgo.HuhbJUezsPgpyD.tVrJraFmegiup.aS","fullName":"管理员","email":"[email protected]","roles":[{"id":1,"name":"管理员","remark":"系统管理员","users":[{"id":1,"username":"admin","password":"$2a$10$.UblZbe8b/ESRiXrajVgo.HuhbJUezsPgpyD.tVrJraFmegiup.aS","fullName":"管理员","email":"[email protected]","roles":[{"id":1,"name":"管理员","remark":"系统管理员","users":[{"id":1,"username":"admin","password":"$2a$10$.UblZbe8b/ESRiXrajVgo.HuhbJUezsPgpyD.tVrJraFmegiup.aS","fullName":"管理员","email":"[email protected]","roles":[{"id":1,"name":"管理员","remark":"系统管理员","users":[{"id":1,"username":"admin","password":"$2a$10$.UblZbe8b/ESRiXrajVgo.HuhbJUezsPgpyD.tVrJraFmegiup.aS","fullName":"管理员","email":"[email protected]","roles":[{"id":1,"name":"管理员","remark":"系统管理员","users":[{"id":1,"username":"admin","password":"$2a$10$.UblZbe8b/ESRiXrajVgo.HuhbJUezsPgpyD.tVrJraFmegiup.aS","fullName":"管理员","email":"[email protected]","roles":[{"id":1,"name":"管理员","remark":"系统管理员","users":[{"id":1,"username":"admin","password":"$2a$10$.UblZbe8b/ESRiXrajVgo.HuhbJUezsPgpyD.tVrJraFmegiup.aS","fullName":"管理员","email":"[email protected]","roles":[{"id":1,"name":"管理员","remark":"系统管理员","users":[{"id":1,"username":"admin","password":"$2a$10$.UblZbe8b/ESRiXrajVgo.HuhbJUezsPgpyD.tVrJraFmegiup.aS","fullName":"管理员","email":"[email protected]","roles":[{"id":1,"name":"管理员","remark":"系统管理员","users":[{"id":1,"username":"admin","password":"$2a$10$.UblZbe8b/ESRiXrajVgo.HuhbJUezsPgpyD.tVrJraFmegiup.aS","fullName":"管理员","email":"[email protected]","roles":[{"id":1,"name":"管理员","remark":"系统管理员","users":[{"id":1,"username":"admin","password":"$2a$10$.UblZbe8b/ESRiXrajVgo.HuhbJUezsPgpyD.tVrJraFmegiup.aS","fullName":"管理员","email":"[email protected]","roles":[{"id":1,"name":"管理员","remark":"系统管理员","users":
...

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

那么要如何解决?

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

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

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 
@Entity
@Table(name = "t_sys_user")
@Data
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String password;
    private String fullName;
    private String email;
    
    @JsonIgnoreProperties("users")
    @ManyToMany(cascade = CascadeType.REMOVE)
    @JoinTable(name = "t_sys_user_roles")
    private List<Role> roles;
}

序列化用户类角色字段里的用户集合字段user.roles[i].users时就忽略该字段
Role类修改如下:


	@JsonIgnoreProperties(value = { "roles" })
    @ManyToMany(cascade = CascadeType.REMOVE, mappedBy = "roles")
    private List<User> users;   //被维护端

返回的结果无user.roles[i].users字段

[{"id":1,"username":"admin","password":"$2a$10$.UblZbe8b/ESRiXrajVgo.HuhbJUezsPgpyD.tVrJraFmegiup.aS","fullName":"管理员","email":"[email protected]","roles":[{"id":1,"name":"管理员","remark":"系统管理员","permissions":[]}],"enabled":true,"version":0,"enabledStr":"有效","authorities":null,"accountNonExpired":true,"accountNonLocked":true,"credentialsNonExpired":true}]

问题解决!

你可能感兴趣的:(jpa)