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

时间:2021-08-11 23:35:46

 

JPA @OneToMany及懒加载无效

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

示例:

 

@OneToMany

teacher 和 student是一对多关系

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

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

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

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

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

我为了验证懒加载是否生效,在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

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

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

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

在正常模式下启动,果然只有一条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”) 就可以了

以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/R_o_b_o_t_/article/details/115400514