评论

收藏

[Java] 解决JPA @OneToMany及懒加载无效的问题

编程语言 编程语言 发布于:2022-02-21 14:43 | 阅读数:512 | 评论:0

这篇文章主要介绍了解决JPA @OneToMany及懒加载无效的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
目录

  • JPA @OneToMany及懒加载无效

    • @OneToMany
    • 小结一下吧

  • 实现JPA的懒加载和无外键

    • 例如
    • 转换时使用


JPA @OneToMany及懒加载无效
@OneToOne @ManyToMany使用不做过多解释,重点解决“懒加载无效问题”。
示例:

@OneToMany
teacher 和 student是一对多关系
DSC0000.png DSC0001.png

DSC0002.jpg

只需要在studentList上使用@OneToMany注解,对应的参数为 懒加载、级联操作、子表外键
DSC0003.png

DSC0004.jpg

我为了验证懒加载是否生效,在debug模式下发现懒加载并没有生效。在正常模式下,返回到页面也是有studentList的数据。于是开始排坑,逐渐怀疑人生。。
直到看到了某国际友人说的这么一句话。
It seems to be a debugging artifact.
At debugging time, because the transaction is still open, the watched lazy loaded entity properties will be loaded at the breakpoint evaluation time.
于是在application.properties中加上spring.jpa.show-sql=true,打开执行的SQL。
debug下,执行到29行,共执行了以下两句SQL:
Hibernate: select teacher0_.id as id1_1_0_, teacher0_.age as age2_1_0_, teacher0_.name as name3_1_0_ from teacher teacher0_ where teacher0_.id=?
Hibernate: select studentlis0_.teacher_id as teacher_4_0_0_, studentlis0_.id as id1_0_0_, studentlis0_.id as id1_0_1_, studentlis0_.addr as addr2_0_1_, studentlis0_.name as name3_0_1_, studentlis0_.teacher_id as teacher_4_0_1_ from student studentlis0_ where studentlis0_.teacher_id=?
开始只查询了teacher表,紧接着进行了关联查询,结合上面那句话猜测可能是debug导致的。而在正常模式下启动,也是两条SQL,猜测可能是返回前端时,序列化自动调用了getStudentList()方法,导致执行了第二条SQL。
于是新建TeacherDto.class
DSC0005.png

并在controller中return teacherDto,不直接返回teacher。
DSC0006.png

在正常模式下启动,果然只有一条SQL,没有进行级联查询。
Hibernate: select teacher0_.id as id1_1_0_, teacher0_.age as age2_1_0_, teacher0_.name as name3_1_0_ from teacher teacher0_ where teacher0_.id=?
至此踩坑结束……

小结一下吧
在使用@OneToOne、@OneToMany、@ManyToMany时,只需要加上参数fetch = FetchType.LAZY即可。
在debug模式下,会自动进行级联查询,导致懒加载无效,可能是idea方便开发人员调试,故意这样设置的。
在接口返回时,避免直接返回entity,可返回Dto或Vo。

实现JPA的懒加载和无外键
在网上找了很多jpa的懒加载,要不就是抓取策略,要不就随便加个fetch=FetchType.LAZY
其实jpa实现懒加载非常简单,其实和mybatis是一样的,就是不要调用对应属性的get方法就可以了

例如
很多接口输出对象时都会用 BeanUtils.copyProperties()将实体转为dto输出,这时候使用它的重载方法copyProperties(Object source, Object target, String… ignoreProperties)就可以实现懒加载了
代码如下
public class NoticeRecord {
  @OneToMany(fetch=FetchType.LAZY)
  @JoinColumn(name = "noticeId",foreignKey = @ForeignKey(name = "null"))
  private List<NoticeSendeeRecord> noticeSendeeRecords;
}
转换时使用
这个重载方法的作用就是转换是忽略noticeRecord中noticeSendeeRecords属性
BeanUtils.copyProperties(noticeRecord,noticeRecordDTO,"noticeSendeeRecords");
这样就实现jpa的懒加载了,检查输出sql语句,也只有查询NoticeRecord 的语句,没有查询NoticeSendeeRecord的语句
而不让jpa产生外键使用 foreignKey = @ForeignKey(name = “null”) 就可以了
以上为个人经验,希望能给大家一个参考,也希望大家多多支持CodeAE代码之家
原文链接:https://blog.csdn.net/R_o_b_o_t_/article/details/115400514

关注下面的标签,发现更多相似文章