使用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自带的级联注解造成死循环问题,解决方法很多种,,开发过程中,根据自己需要解决

相关推荐
追逐时光者4 小时前
一款使用 C# 编写专为 Windows 11 打造的文件资源管理器增强工具!
后端·.net
风象南5 小时前
普通人用AI加持赚到的第一个100块
人工智能·后端
皮皮林5516 小时前
Java性能调优黑科技!1行代码实现毫秒级耗时追踪,效率飙升300%!
java
冰_河7 小时前
QPS从300到3100:我靠一行代码让接口性能暴涨10倍,系统性能原地起飞!!
java·后端·性能优化
JavaGuide9 小时前
7 道 RAG 基础概念知识点/面试题总结
前端·后端
桦说编程9 小时前
从 ForkJoinPool 的 Compensate 看并发框架的线程补偿思想
java·后端·源码阅读
格砸10 小时前
从入门到辞职|从ChatGPT到OpenClaw,跟上智能时代的进化
前端·人工智能·后端
蝎子莱莱爱打怪11 小时前
GitLab CI/CD + Docker Registry + K8s 部署完整实战指南
后端·docker·kubernetes
躺平大鹅11 小时前
Java面向对象入门(类与对象,新手秒懂)
java