使用Jpa自带的级联注解造成死循环问题

前言

使用Jpa持久化框架级联注解@OneToOne或者@OneToMany等。双向关联查询时,会造成数据死循环

例子

实体类定义

1、定义一个部门实体类

less 复制代码
@Data
@Entity
@Table(name = "t_department")
public class Department {

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

    private String name;

    @OneToMany(mappedBy = "department", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Employee> employees;

}

2、定义一个销售实体类

less 复制代码
@Data
@Entity
@Table(name = "t_employee")
public class Employee {

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

    private String name;


    @ManyToOne
    @JoinColumn(name = "department_id")
    private Department department;

}

双向关联 3、dao层定义

kotlin 复制代码
@Repository
public interface DepartmentRepository extends JpaRepository<Department, Long>,
        JpaSpecificationExecutor<Department> {


}

4、

kotlin 复制代码
@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long>,
        JpaSpecificationExecutor<Employee> {


}

5、接口定义

typescript 复制代码
@RestController
public class IndexController {

    @Autowired
    private DepartmentRepository departmentRepository;

    @GetMapping("/index")
    public String index() {;
        Department department = new Department();
        department.setName("bbb");
        Employee employee = new Employee();
        employee.setName("aaa");
        employee.setDepartment(department);
        department.setEmployees(List.of(employee));
        departmentRepository.save(department);
        return "success";
    }


    @GetMapping("/findById")
    public Department findById(@RequestParam Long id) {
        return departmentRepository.findById(id).orElse(null);
    }
}

6、调用

bash 复制代码
http://ip:端口/index

保存数据

7、 这个时候,调用

bash 复制代码
http://ip:端口/findById?id=2

会发现数据出现死循环

这个并不是bug,这个在toString()方法中,一层一层嵌套导致的,只需要中断其嵌套就行

解决方法

1、 使用@JsonIgnoreProperties中断其死循环

less 复制代码
@Data
@Entity
@Table(name = "t_department")
public class Department {

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

    private String name;

    @JsonIgnoreProperties({"department"})
    @OneToMany(mappedBy = "department", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Employee> employees;

}

在实体类两边都加上,再次访问,数据为

2、 使用实体类dto

定义一个实体类

kotlin 复制代码
@Data
public class DepartmentDto {

    private Long id;

    private String name;

}
less 复制代码
@GetMapping("/findById1")
public DepartmentDto findById1(@RequestParam Long id) {
    Department department = departmentRepository.findById(id).orElse(null);
    DepartmentDto departmentDto = new DepartmentDto();
    BeanUtils.copyProperties(department, departmentDto);
    return departmentDto;
}

3、 使用 @JsonIgnore注解

less 复制代码
@Data
@Entity
@Table(name = "t_department")
public class Department {

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

    private String name;

    @JsonIgnore
    @OneToMany(mappedBy = "department", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Employee> employees;

}

总结

使用Jpa自带的级联注解造成死循环问题,解决方法很多种,,开发过程中,根据自己需要解决

相关推荐
江华森1 小时前
深入理解 Flask 实现原理
后端·python·flask
Nturmoils1 小时前
LEFT JOIN 到底什么时候会被优化器偷偷改写成 INNER JOIN
后端
人道领域2 小时前
【0-1的agent进阶篇】Prompt 与上下文工程
java·开发语言·prompt·mcp
KINGSEA_1682 小时前
AgentScope Java 2.0 架构解析
java
北冥you鱼2 小时前
Go Modules 使用指南:从入门到精通
开发语言·后端·golang
嘟嘟07172 小时前
从零理解 MCP:手写一个本地 MCP Server 并接入 LangChain Agent
前端·后端
沈七2 小时前
Go 补强第三天:给 TaskStore 写单元测试
后端
范闲2 小时前
第二章:Octo v0.1.1:从「能用」到「好用」——终端 AI 聊天体验的全面升级
人工智能·后端
贰先生2 小时前
Xiuno BBS 审计之问题03:附件上传高危风险
后端
Ai拆代码的曹操3 小时前
记一次 K8s Pod Pending 排查:两层坑叠加,从资源到存储的完整复盘
后端