解决JPA @OneToMany及懒加载无效的问题
作者:Robot6540
JPA @OneToMany及懒加载无效
@OneToOne @ManyToMany使用不做过多解释,重点解决“懒加载无效问题”。
示例:
@OneToMany
teacher 和 student是一对多关系
只需要在studentList上使用@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
并在controller中return teacherDto,不直接返回teacher。
在正常模式下启动,果然只有一条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”) 就可以了
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。