JPA @ManyToMany java.lang.StackOverflowError: null

简介: JPA 懒加载的一个坑 大神可绕路package com.liuzm.controller;import com.

JPA 懒加载的一个坑 大神可绕路

package com.liuzm.controller;

import com.liuzm.entity.UacRole;
import com.liuzm.entity.UacUser;
import com.liuzm.service.UacUserService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.Set;

@RestController
public class UserController {

    @Resource
    private UacUserService uacUserService;

    @GetMapping("/")
    public Set<UacRole> findByLoginName() {
        UacUser uacUser = this.uacUserService.findByLoginName("admin");
        System.out.println(uacUser);
        Set<UacRole> roles = uacUser.getRoles();
        System.out.println(roles.size());
        return roles;
    }
}

package com.liuzm.entity;

import com.fasterxml.jackson.annotation.JsonIgnore;

import javax.persistence.*;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

@Entity
@Table(name = "tbl_uac_role")
public class UacRole implements Serializable {
    /**
     * serialVersionUID:用一句话描述这个变量表示什么.
     * @since JDK 1.7
     */
    private static final long serialVersionUID = -6263200210499558891L;

    /**
     * ID
     */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    /**
     * 角色编码
     */
    @Column(name = "role_code")
    private String roleCode;
    @JsonIgnore
    @ManyToMany
    @JoinTable(name = "tbl_uac_role_user", joinColumns = {@JoinColumn(name = "role_id", referencedColumnName = "id")}, inverseJoinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")})
    private Set<UacUser> users = new HashSet<>();

    public UacRole() {
    }

    public UacRole(Long id) {
        this.id = id;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getRoleCode() {
        return roleCode;
    }

    public void setRoleCode(String roleCode) {
        this.roleCode = roleCode;
    }

    public Set<UacUser> getUsers() {
        return users;
    }

    public void setUsers(Set<UacUser> users) {
        this.users = users;
    }

    @Override
    public String toString() {
        return "UacRole{" +
                "id=" + id +
                ", roleCode='" + roleCode + '\'' +
                ", users=" + users +
                '}';
    }
}
package com.liuzm.entity;

import com.fasterxml.jackson.annotation.JsonIgnore;

import javax.persistence.*;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

@Entity
@Table(name = "tbl_uac_user")
public class UacUser implements Serializable {
    /**
     * serialVersionUID:用一句话描述这个变量表示什么.
     * @since JDK 1.7
     */
    private static final long serialVersionUID = 3439493474130693948L;

    /**
     * ID
     */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    /**
     * 登录名
     */
    @Column(name = "login_name")
    private String loginName;
    @ManyToMany(mappedBy = "users")
    @JsonIgnore
    private Set<UacRole> roles = new HashSet<>();

    @Override
    public String toString() {
        return "UacUser{" +
                "id='" + id + '\'' +
                ", loginName='" + loginName + '\'' +
                ", roles=" + roles +
                '}';
    }



    public UacUser() {
    }
    public UacUser(Long id) {
        this.id = id;
    }


    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getLoginName() {
        return loginName;
    }

    public void setLoginName(String loginName) {
        this.loginName = loginName;
    }

    public Set<UacRole> getRoles() {
        return roles;
    }

    public void setRoles(Set<UacRole> roles) {
        this.roles = roles;
    }
}

package com.liuzm.repository;

import com.liuzm.entity.UacUser;
import org.springframework.data.jpa.repository.JpaRepository;


public interface UacUserRepository extends JpaRepository<UacUser, Long> {

    UacUser findByLoginName(String loginName);
}

package com.liuzm.service;

import com.liuzm.entity.UacUser;

public interface UacUserService {

    UacUser findByLoginName(String loginName);
}

server:
  port: 8000
  tomcat:
    uri-encoding: UTF-8
spring:
  application:
    name: jpa-test
  jpa:
      generate-ddl: false
      show-sql: true
      hibernate:
        ddl-auto: update
      properties:
        hibernate:
          dialect: org.hibernate.dialect.MySQL5Dialect
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost/test?useUnicode=true&characterEncoding=UTF-8
    username: root
    password: 123456
logging:
  level:
    root: INFO
    org.hibernate: INFO
    org.hibernate.type.descriptor.sql.BasicBinder: TRACE
    org.hibernate.type.descriptor.sql.BasicExtractor: TRACE

错误如下

Hibernate: select uacuser0_.id as id1_2_, uacuser0_.login_name as login_na2_2_ from tbl_uac_user uacuser0_ where uacuser0_.login_name=?
2017-04-19 13:49:46.187 TRACE 14504 --- [nio-8000-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [VARCHAR] - [admin]
2017-04-19 13:49:46.191 TRACE 14504 --- [nio-8000-exec-1] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([id1_2_] : [BIGINT]) - [222]
2017-04-19 13:49:46.195 TRACE 14504 --- [nio-8000-exec-1] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([login_na2_2_] : [VARCHAR]) - [admin]
Hibernate: select roles0_.user_id as user_id2_1_0_, roles0_.role_id as role_id1_1_0_, uacrole1_.id as id1_0_1_, uacrole1_.role_code as role_cod2_0_1_ from tbl_uac_role_user roles0_ inner join tbl_uac_role uacrole1_ on roles0_.role_id=uacrole1_.id where roles0_.user_id=?
2017-04-19 13:49:46.208 TRACE 14504 --- [nio-8000-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [BIGINT] - [222]
2017-04-19 13:49:46.213 TRACE 14504 --- [nio-8000-exec-1] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([id1_0_1_] : [BIGINT]) - [1234]
2017-04-19 13:49:46.213 TRACE 14504 --- [nio-8000-exec-1] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([role_cod2_0_1_] : [VARCHAR]) - [admin]
2017-04-19 13:49:46.214 TRACE 14504 --- [nio-8000-exec-1] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([user_id2_1_0_] : [BIGINT]) - [222]
2017-04-19 13:49:46.214 TRACE 14504 --- [nio-8000-exec-1] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([role_id1_1_0_] : [BIGINT]) - [1234]
Hibernate: select users0_.role_id as role_id1_1_0_, users0_.user_id as user_id2_1_0_, uacuser1_.id as id1_2_1_, uacuser1_.login_name as login_na2_2_1_ from tbl_uac_role_user users0_ inner join tbl_uac_user uacuser1_ on users0_.user_id=uacuser1_.id where users0_.role_id=?
2017-04-19 13:49:46.217 TRACE 14504 --- [nio-8000-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [BIGINT] - [1234]
2017-04-19 13:49:46.218 TRACE 14504 --- [nio-8000-exec-1] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([id1_2_1_] : [BIGINT]) - [222]
2017-04-19 13:49:46.218 TRACE 14504 --- [nio-8000-exec-1] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([role_id1_1_0_] : [BIGINT]) - [1234]
2017-04-19 13:49:46.218 TRACE 14504 --- [nio-8000-exec-1] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([user_id2_1_0_] : [BIGINT]) - [222]
2017-04-19 13:49:46.271 ERROR 14504 --- [nio-8000-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.StackOverflowError] with root cause

java.lang.StackOverflowError: null
    at java.util.AbstractCollection.toString(AbstractCollection.java:454) ~[na:1.8.0_60]
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:300) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at java.lang.String.valueOf(String.java:2994) ~[na:1.8.0_60]
    at java.lang.StringBuilder.append(StringBuilder.java:131) ~[na:1.8.0_60]
    at com.liuzm.entity.UacUser.toString(UacUser.java:37) ~[classes/:na]
    at java.lang.String.valueOf(String.java:2994) ~[na:1.8.0_60]
    at java.lang.StringBuilder.append(StringBuilder.java:131) ~[na:1.8.0_60]
    at java.util.AbstractCollection.toString(AbstractCollection.java:462) ~[na:1.8.0_60]
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:300) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at java.lang.String.valueOf(String.java:2994) ~[na:1.8.0_60]
    at java.lang.StringBuilder.append(StringBuilder.java:131) ~[na:1.8.0_60]
    at com.liuzm.entity.UacRole.toString(UacRole.java:69) ~[classes/:na]
    at java.lang.String.valueOf(String.java:2994) ~[na:1.8.0_60]
    at java.lang.StringBuilder.append(StringBuilder.java:131) ~[na:1.8.0_60]
    at java.util.AbstractCollection.toString(AbstractCollection.java:462) ~[na:1.8.0_60]
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:300) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at java.lang.String.valueOf(String.java:2994) ~[na:1.8.0_60]
    at java.lang.StringBuilder.append(StringBuilder.java:131) ~[na:1.8.0_60]
    at com.liuzm.entity.UacUser.toString(UacUser.java:37) ~[classes/:na]
    at java.lang.String.valueOf(String.java:2994) ~[na:1.8.0_60]
    at java.lang.StringBuilder.append(StringBuilder.java:131) ~[na:1.8.0_60]
    at java.util.AbstractCollection.toString(AbstractCollection.java:462) ~[na:1.8.0_60]
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:300) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at java.lang.String.valueOf(String.java:2994) ~[na:1.8.0_60]
    at java.lang.StringBuilder.append(StringBuilder.java:131) ~[na:1.8.0_60]
    at com.liuzm.entity.UacRole.toString(UacRole.java:69) ~[classes/:na]
    at java.lang.String.valueOf(String.java:2994) ~[na:1.8.0_60]
    at java.lang.StringBuilder.append(StringBuilder.java:131) ~[na:1.8.0_60]
    at java.util.AbstractCollection.toString(AbstractCollection.java:462) ~[na:1.8.0_60]
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:300) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at java.lang.String.valueOf(String.java:2994) ~[na:1.8.0_60]
    at java.lang.StringBuilder.append(StringBuilder.java:131) ~[na:1.8.0_60]
    at com.liuzm.entity.UacUser.toString(UacUser.java:37) ~[classes/:na]
    at java.lang.String.valueOf(String.java:2994) ~[na:1.8.0_60]
    at java.lang.StringBuilder.append(StringBuilder.java:131) ~[na:1.8.0_60]
    at java.util.AbstractCollection.toString(AbstractCollection.java:462) ~[na:1.8.0_60]
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:300) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at java.lang.String.valueOf(String.java:2994) ~[na:1.8.0_60]
    at java.lang.StringBuilder.append(StringBuilder.java:131) ~[na:1.8.0_60]
    at com.liuzm.entity.UacRole.toString(UacRole.java:69) ~[classes/:na]
    at java.lang.String.valueOf(String.java:2994) ~[na:1.8.0_60]
    at java.lang.StringBuilder.append(StringBuilder.java:131) ~[na:1.8.0_60]
    at java.util.AbstractCollection.toString(AbstractCollection.java:462) ~[na:1.8.0_60]
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:300) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at java.lang.String.valueOf(String.java:2994) ~[na:1.8.0_60]
    at java.lang.StringBuilder.append(StringBuilder.java:131) ~[na:1.8.0_60]
    at com.liuzm.entity.UacUser.toString(UacUser.java:37) ~[classes/:na]
    at java.lang.String.valueOf(String.java:2994) ~[na:1.8.0_60]
    at java.lang.StringBuilder.append(StringBuilder.java:131) ~[na:1.8.0_60]
    at java.util.AbstractCollection.toString(AbstractCollection.java:462) ~[na:1.8.0_60]
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:300) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at java.lang.String.valueOf(String.java:2994) ~[na:1.8.0_60]
    at java.lang.StringBuilder.append(StringBuilder.java:131) ~[na:1.8.0_60]
    at com.liuzm.entity.UacRole.toString(UacRole.java:69) ~[classes/:na]
    at java.lang.String.valueOf(String.java:2994) ~[na:1.8.0_60]
    at java.lang.StringBuilder.append(StringBuilder.java:131) ~[na:1.8.0_60]
    at java.util.AbstractCollection.toString(AbstractCollection.java:462) ~[na:1.8.0_60]
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:300) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at java.lang.String.valueOf(String.java:2994) ~[na:1.8.0_60]

在网上查了一下,和大神们的问题略有不同,这里具体原因是 两个类都有toString(), 而两个类中同时使用了懒加载(默认)这样在A类toString的时候会发sql查询B类,而B类toString()又会发sql查A类这样会发生死循环最后导致java.lang.StackOverflowError.初用JPA 出现问题引以为鉴.

完整代码

demo

最后做一下说明 如果是springmvc jackson报response错误 那么最好是 多对多维护关系都不要toString() Set集合对象, 然后使用 dto 或者 vo 去做数据的传输去解决这个问题. 具体原因有待日后解决

目录
相关文章
|
3月前
|
Java 测试技术
Java系列之判断字符串是为空或者null
这篇文章介绍了如何在Java中使用`isEmpty()`方法判断字符串是否为空或`null`,并提供了相应的测试用例来演示其用法。
|
3月前
|
IDE Java 测试技术
如何优雅地根治Java中Null值引起的Bug问题
【8月更文挑战第18天】在Java开发中,null 值是一个既常见又危险的存在。它常常是导致程序崩溃、难以调试的“罪魁祸首”。然而,通过一系列优雅的策略和实践,我们可以有效地减少甚至根除由 null 值引发的Bug。本文将从多个方面探讨如何做到这一点。
78 4
|
3月前
|
存储 JavaScript Java
Java中未被初始化的字符串打印出“null”?
在Java中,未初始化的`String`变量默认值为`null`。打印此类变量时输出“null”,是因为`PrintStream`类中的`print`方法特别处理了`null`值,将其转换为字符串“null”。从JDK 17开始,`println`方法通过`String.valueOf`间接实现相同功能。当拼接包含`null`的字符串时,如`s1 + &quot;BLACK&quot;`,结果为“nullBLACK”,这是因为字符串构建过程中`StringBuilder`的`append`方法将`null`转换为“null”。
|
3月前
|
NoSQL Java Redis
【Azure Spring Cloud】Java Spring Cloud 应用部署到Azure上后,发现大量的 java.lang.NullPointerException: null at io.lettuce.core.protocol.CommandHandler.writeSingleCommand(CommandHandler.java:426) at ... 异常
【Azure Spring Cloud】Java Spring Cloud 应用部署到Azure上后,发现大量的 java.lang.NullPointerException: null at io.lettuce.core.protocol.CommandHandler.writeSingleCommand(CommandHandler.java:426) at ... 异常
|
3月前
|
Java 程序员 开发者
Java之! = null判空
总之,`!= null`的判空技巧对于任何使用Java进行开发的程序员都是基本功,它有助于维护代码的清晰度和安全性,在编写可靠和维护性强的软件应用时扮演着关键角色。掌握这个简单却重要的技术,将对任何Java开发者的职业生涯大有裨益。
69 0
|
5月前
|
Java 数据处理 Apache
探讨Java中判断String类型为空和null的方法
探讨Java中判断String类型为空和null的方法
58 1
|
6月前
|
安全 Java 开发者
Java一分钟之-Optional类:优雅处理null值
【5月更文挑战第13天】Java 8的`Optional`类旨在减少`NullPointerException`,提供优雅的空值处理。本文介绍`Optional`的基本用法、创建、常见操作,以及如何避免错误,如直接调用`get()`、误用`if (optional != null)`检查和过度使用`Optional`。正确使用`Optional`能提高代码可读性和健壮性,建议结合实际场景灵活应用。
226 3
|
5月前
|
安全 算法 Java
Java8实战-用Optional取代null
Java8实战-用Optional取代null
27 0
|
5月前
|
Web App开发 分布式计算 大数据
MaxCompute操作报错合集之配置归并节点,出现java.lang.NullPointerException: null错误提示,该怎么办
MaxCompute是阿里云提供的大规模离线数据处理服务,用于大数据分析、挖掘和报表生成等场景。在使用MaxCompute进行数据处理时,可能会遇到各种操作报错。以下是一些常见的MaxCompute操作报错及其可能的原因与解决措施的合集。
|
5月前
|
Java
Java中判断String类型为空和null的方法
Java中判断`String`变量是否为空或`null`需用`== null`和`.isEmpty()`。示例代码提供两种方法:`main`方法直接判断,`safeGetString`方法提供默认值。当输入为`null`或空时,返回默认值。代码包含三个测试案例,分别处理`null`、空字符串和非空非`null`字符串。
113 0