春季靴子,多对一关系获取LAZY或EAGER

时间:2019-06-20 13:17:12

标签: java json hibernate spring-boot

两个具有一对多关系的实体。

实体A指向实体B的列表,列表最多为几个。实体B反向引用了A。

当显示为JSON时,我希望看到A带有多个B或B带有对应的A。但这似乎取决于@OneToMany或@ManyToOne批注中的提取策略。

我读过的大多数东西都说@ManyToOne应该是LAZY,而@OneToMany应该是EAGER。这种方法将在列出实体A时起作用; JSON中显示了每个A及其关联的B。

但是在列出B时,出现错误

  

类型定义错误:[简单类型,类   org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor];嵌套的   例外是   com.fasterxml.jackson.databind.exc.InvalidDefinitionException:否   找到用于类的序列化器   org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor且不   发现的用于创建BeanSerializer的属性(为避免出现异常,   禁用SerializationFeature.FAIL_ON_EMPTY_BEANS

将LAZY更改为EAGER可解决此问题。但是,对于LAZY,我希望它至少能带来B记录。错误是令人惊讶的。

我将添加两个实体定义都使用JsonIdentityInfo(为防止无限递归而添加),它使用了SimpleObjectIdResolver。

因此,总而言之,我感到困惑。我可以使它“起作用”,但不确定为什么。

1 个答案:

答案 0 :(得分:0)

  

我读过的大多数东西都说@ManyToOne应该是LAZY,而@OneToMany应该是EAGER。这种方法将在列出实体A时起作用; JSON中显示了每个A及其关联的B。

这不是应该执行的操作,而是默认操作。可以在@ManyToOne-和@OneToMany文档中看到。各个用例之间应采取的措施各不相同。


作为例外:如果使用延迟加载定义了关系,则将插入代理对象,并在需要时从数据库中获取真实实体。 Jackson尝试序列化代理,但失败。这暗示了一个更深层次的架构设计缺陷:为什么要尝试序列化数据库实体?数据库和序列化过程(例如,通过DTO转换)之间应该至少有一层。

即使序列化可以按预期进行(即,丢失的实体已被提取),加载实体的事务也很可能已经关闭,并且该过程将导致LazyInitializationException。如果您预先知道始终需要获取关系,请使其热切获取。如果仅在某些情况下需要获取关系,请在JPQL中对获取进行编码,如有必要,可以在本机查询中对CriteriaQuery进行编码。提取延迟加载的@OneToMany关系将导致N+1 problem,不惜一切代价避免。