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

相关推荐
码事漫谈2 小时前
黄仁勋被裁第一天,就收到了橄榄枝
后端
金銀銅鐵3 小时前
带您看懂字节码指令(二):空循环里有什么
java·后端·ai编程
皮皮林5514 小时前
比 Xshell 还好用的 SSH 客户端神器,MobaXterm 太爱了!
后端
吴名氏.4 小时前
Java转AI Agent教程(第十三周)混合检索与重排
java·数据库·人工智能·ai·ai agent
我不会起名字3225 小时前
会话缓存失效排查:区分 Redis 失效与节点广播
redis·后端·go·即时通讯·im·故障排查
.痞老板.5 小时前
java ee--多线程(进阶)
java·java-ee
深入云栈6 小时前
Netty 4.2.x 源码深度解析 (二十三):ByteBuf 核心设计 —— 索引、类型与零拷贝
java·后端·架构
JackJiang6 小时前
IM踩坑:聊天消息ID怎么设计?一个UUID搞不定,我用双ID解决
后端·架构
开心猴爷7 小时前
iOS 上架 App 流程
后端·ios
code_Bo7 小时前
不只命令行:我把跨 Agent 会话同步做成了桌面应用
前端·javascript·后端