如何解决循环引用的问题

简介: 解决循环引用的问题

概念说明

循环引用是指在对象之间存在相互引用的情况。具体来说,当一个对象A引用了另一个对象B,而对象B又引用了对象A,它们之间形成了一个循环引用关系。

 循环引用可能会导致一些问题,特别是在序列化和反序列化过程中。在序列化过程中,如果不进行特殊处理,循环引用会导致无限递归的序列化,最终导致栈溢出异常。在反序列化过程中,循环引用可能会导致对象的重复创建,破坏对象的一致性。

发现问题

 当我们实现了类之间的多对多关系的时候,当我们从数据库中查询相关数据的时候,会发现查询出来的结果会存在对象之间嵌套的问题,最后导致堆栈溢出的问题。

Classes类

@Service
@Entity
@Table(name="Classes")
public class Classes implements ApplicationRunner {
    private Long id;
    private Long classId;
    private String className;
    private Integer isDelete;
    @OneToMany(mappedBy = "classes")
    private List<ClassesActor> actorClasses;
  //getter和setter方法
  }

Actor类

@Service
@Entity
@Table(name = "Actor")
public class Actor  {
    private Long id;
    private String code;
    private String name;
    private String phone;
  @OneToMany(mappedBy = "actor")
    private List<ClassesActor> actorClasses;
  //getter和setter方法
  }

ClassesActor类

@Entity
public class ClassesActor {
    private Long id;
    @ManyToOne
    @JoinColumn(name = "actor_id")
    private Actor actor;
    @ManyToOne
    @JoinColumn(name = "class_id")
    private Classes classes;
  //getter和setter方法
  }

当我在实际的业务中去查询classes相关信息的时候会发现,Classes对象中有ClassesActor对象,点开ClassesActor对象中海油Classes对象而且这些对象都是同一个对象。所以就出现了循环嵌套的问题。

2349f43025d24c2f9f32073e1414d1de.png

解决问题

分析问题

  1. 我们要清楚对于对象的属性进行操作属于数据序列化的过程。数据序列化是将对象转换为字节流或其他形式的数据,以便在网络传输、存储或跨平台传递时使用。在数据序列化过程中,对象的属性值会被转换为字节流或其他格式的数据,并随后可以被反序列化为对象。

 2.通过对问题的分析我们可以通过序列化操作来解决序列化多个相同对象的问题,这样我们就把问题缩小到序列化中。

 3.明确如何在序列化的过程中去控制相同的对象只序列化一次,我们的问题也就迎刃而解了。

具体解决

 通过@JsonManagedReference和@JsonBackReference注解帮助我们解决相同的对象只序列化一次的问题。

注解说明

「@JsonManagedReference 」注解用于标注在实体类的属性上,表示该属性是一个“被管理的引用”。它的作用是告诉Jackson在序列化过程中,该属性是“正向”引用,需要被序列化输出。同时,它还需要配合@JsonBackReference注解一起使用,指定“反向”引用的属性。

「@JsonBackReference 」 注解用于标注在实体类的属性上,表示该属性是一个“反向引用”。它的作用是告诉Jackson在序列化过程中,该属性是“反向”引用,不需要被序列化输出。相反,它会通过@JsonManagedReference注解指定的属性来进行序列化输出。

代码实现

Classes类

@Service
@Entity
@Table(name="Classes")
public class Classes implements ApplicationRunner {
    private Long id;
    private Long classId;
    private String className;
    private Integer isDelete;
    @OneToMany(mappedBy = "classes")
  @JsonManagedReference(value = "class-actorClasses")
    private List<ClassesActor> actorClasses;
  //getter和setter方法
  }

Actor类

@Service
@Entity
@Table(name = "Actor")
public class Actor  {
    private Long id;
    private String code;
    private String name;
    private String phone;
  @OneToMany(mappedBy = "actor")
  @JsonManagedReference(value = "actor-classes")
    private List<ClassesActor> actorClasses;
  //getter和setter方法
  }

ClassesActor类

@Entity
public class ClassesActor {
    private Long id;
    @ManyToOne
    @JoinColumn(name = "actor_id")
    @JsonBackReference(value = "actor-classes")
    private Actor actor;
    @ManyToOne
    @JoinColumn(name = "class_id")
    @JsonBackReference(value = "class-actorClasses")
    private Classes classes;
  //getter和setter方法
  }

通过使用@JsonManagedReference和@JsonBackReference注解,Jackson库能够正确处理实体类之间的循环引用关系,避免了无限递归的序列化问题。当一个类中出现了多个@JsonBackReference注解要有value值进行区分和加以对应。

效果展示

062accd40b57402daa5e76fa46e46801.png

总结提升

 这两个注解只适用于序列化过程,对于反序列化过程是不起作用的。如果需要在反序列化时处理循环引用问题,可以考虑使用@JsonIdentityInfo注解或自定义序列化和反序列化逻辑来处理。


相关文章
|
6月前
|
存储 JavaScript 前端开发
|
6月前
|
C++
记录一次循环引用的问题
记录一次循环引用的问题
|
1月前
|
存储 JavaScript 前端开发
什么是循环引用现象呢
【10月更文挑战第13天】什么是循环引用现象呢
22 0
|
27天前
|
缓存 Java 测试技术
如何避免内存泄漏
【10月更文挑战第19天】如何避免内存泄漏
27 0
|
4月前
|
算法 Java Python
分代回收在Python中是如何解决循环引用问题的?
【7月更文挑战第2天】分代回收在Python中是如何解决循环引用问题的?
35 0
|
5月前
|
监控 算法 Java
掌握Java内存管理:对象生命周期与垃圾回收机制
本文旨在为读者提供一次深入的探索之旅,穿越Java虚拟机(JVM)的迷宫,揭示对象从诞生到消亡的奥秘。我们将一起揭开内存分配、存活判定以及回收策略等概念背后的神秘面纱,通过案例分析与实践技巧,让读者能够更加高效地运用Java语言,优化程序性能。
|
5月前
|
Web App开发 存储 JavaScript
如何避免闭包函数的内存泄漏
如何避免闭包函数的内存泄漏
47 0
|
6月前
|
架构师 编译器 程序员
内存泄露专题(1)何为内存泄露
内存泄露专题(1)何为内存泄露
45 1
|
6月前
|
存储 C++
什么是内存泄漏?如何避免内存泄漏?
什么是内存泄漏?如何避免内存泄漏?
56 0
|
6月前
|
JavaScript Java
JS内存泄漏是什么 什么情况下会出现内存泄漏 内存泄漏怎么解决
JS内存泄漏是什么 什么情况下会出现内存泄漏 内存泄漏怎么解决
35 0