Spring Data JPA查询报错java.lang.StackOverflowError hibernate SpringBoot
toString()造成死循环,重写toString()方法
现象
测试JPA的多对多查询时,有一个User对象,该User有多个Role,然后报错
User
@Data
@Entity
@Table(name = "user")
public class User {
@Id
// 主键自动增长
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
Integer id;
@Column(name = "username")
String username;
@Column(name = "password")
String password;
/**
* 多对多关系会在创建用户和新角色时级联新增,关联表为user_role,当前对象在关联表对应的外键,和另一方在关联表中对应的外键
*/
@ManyToMany(targetEntity = Role.class, cascade = CascadeType.MERGE, fetch = FetchType.LAZY)
@JoinTable(name = "user_role",
joinColumns = {@JoinColumn(name = "u_id", referencedColumnName = "id")},
inverseJoinColumns = {@JoinColumn(name = "r_id", referencedColumnName = "id")})
List<Role> roles = new ArrayList<>();
}
Role
@Data
@Entity
@Table(name = "role")
public class Role{
@Id
// 自增
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
Integer id;
@Column(name = "role")
String role;
// 用户角色多对多
@ManyToMany(mappedBy = "roles",fetch = FetchType.LAZY)
List<User> users = new ArrayList<>();
}
Test
// 存在“一/多对多"的情况时,需要添加事务,作为一个整体
@Transactional(readOnly = true)
@Test
void select() {
List<User> all = userRepository.findAll();
System.out.println(all);
}
Console
java.lang.StackOverflowError
at java.base/java.lang.StringConcatHelper.stringOf(StringConcatHelper.java:453)
at com.example.springbootsecurityconcise.bean.Role.toString(Role.java:53)
at java.base/java.lang.String.valueOf(String.java:4218)
at java.base/java.lang.StringBuilder.append(StringBuilder.java:173)
at java.base/java.util.AbstractCollection.toString(AbstractCollection.java:457)
at org.hibernate.collection.spi.PersistentBag.toString(PersistentBag.java:590)
at java.base/java.lang.StringConcatHelper.stringOf(StringConcatHelper.java:453)
at com.example.springbootsecurityconcise.bean.User.toString(User.java:62)
at java.base/java.lang.String.valueOf(String.java:4218)
at java.base/java.lang.StringBuilder.append(StringBuilder.java:173)
at java.base/java.util.AbstractCollection.toString(AbstractCollection.java:457)
// ...
原因
查看报错信息,StackOverflowError应该是哪里造成了死循环,多对多属性在创建时双方都有对方的List<Xxx>属性,在输出查看时使用了System.out.println(),会调用对象的toString()方法,在Xxx.toString()中输出Yyy时,又会调用Yyy.toString(),而Yyy.toString()中又有Xxx,就会死循环
解决
重写toString()方法,手动调用User.getXxx()方法,或减去另一方在toString()中的输出
/**
* 重写toString()方法,否则在sout输出时,会导致两个对象的toString()相互调用,现在需要去掉一方的关联字段输出
* java.lang.StackOverflowError
* @return
*/
@Override
public String toString() {
return "Role{" +
"id=" + id +
", role='" + role + '\'' +
// ", users=" + users +
'}';
}