使用Spring Data JPA的坑点记录总结
前言
spring-data-jpa的基本介绍:jpa诞生的缘由是为了整合第三方orm框架,建立一种标准的方式,百度百科说是jdk为了实现orm的天下归一,目前也是在按照这个方向发展,但是还没能完全实现。在orm框架中,hibernate是一支很大的部队,使用很广泛,也很方便,能力也很强,同时hibernate也是和jpa整合的比较良好,我们可以认为jpa是标准,事实上也是,jpa几乎都是接口,实现都是hibernate在做,宏观上面看,在jpa的统一之下hibernate很良好的运行。
最近在使用springboot 以及spring data jpa ,使用jpa可以让我更方便的操作数据库,但在使用中也遇到了不少的坑,下面这篇文章就来记录下,下面话不多说了,来一起看看详细的介绍吧。
场景:
动态查询,分页查询,根据传入不同的状态,分别查询不同数据表,并且在传入page对象之前用map进行vo转换。而pageable的使用地方不同影响到了分页数据的正确性,以此进行探讨。
- pageable使用于new pageimpl<>中,且直到最后才将list -> page
- pageable使用于findall()中
前提:
page对象封于vo内,返回数据包括了分页数据
@apimodelproperty("记录") private page<activityrecordvo> activityrecordvolist; @apimodelproperty("数量") private integer num = 0; @apimodelproperty("金额") private bigdecimal totalmoney = bigdecimal.valueof(0);
错误运用:
list<activityrecordvo> activityrecordvolist = new arraylist<>(); if (receivesendrecordrequestvo.getsendorreceivetype() == sendorreceivetype.receive) { list<challengerecord> challengerecordlist = challengerecorddao.findbyuseridanddeletetype(userid, deletetype.false); if (!collectionutils.isempty(challengerecordlist)) { activityrecordvolist = challengerecordlist.stream() .map(this::challengerecordtoactivityrecordvo) .collect(collectors.tolist()); } } else if (receivesendrecordrequestvo.getsendorreceivetype() == sendorreceivetype.send) { list<activity> activitylist = activitydao.findbyuseridanddeletetype(userid, deletetype.false); if (!collectionutils.isempty(activitylist)) { activityrecordvolist = activitylist.stream() .map(this::activitytoactivityrecordvo) .collect(collectors.tolist()); } }
activityreceivesendrecordvo.setactivityrecordvolist(new pageimpl<>(activityrecordvolist, pageable, activityrecordvolist.size()));
解析:传入的pageable只在set进vo的时候,用new pageiml将list转为page对象,前端报的问题 虽然总页数、总条数均为正确,但第一页的条数是全部 ,数据异常!
正确参考做法:
采用specifications先根据查询条件动态查询并map出相应分页对象(此块代码因需求而异),这时 findall 传入的pageable是生效的,便会显现正确的分页信息。
代码块参考:
xxxcommonspecutil 是自封的specification工具类,与原生spring data jpa原生查询方法类似。
page<activityrecordvo> page = new pageimpl<>(activityrecordvolist, pageable, activityrecordvolist.size()); if (receivesendrecordrequestvo.getsendorreceivetype() == sendorreceivetype.receive) { specifications<challengerecord> spec = specifications.where( challengecommonspecutil.equal("userid", userid)) .and(challengecommonspecutil.equal("deletetype", deletetype.false)); page = challengerecorddao.findall(spec, pageable).map(this::challengerecordtoactivityrecordvo); } else if (receivesendrecordrequestvo.getsendorreceivetype() == sendorreceivetype.send) { specifications<activity> spec = specifications.where( activitycommonspecutil.equal("userid", userid)) .and(activitycommonspecutil.equal("deletetype", deletetype.false)); page = activitydao.findall(spec, pageable).map(this::activitytoactivityrecordvo); }
注:activityreceivesendrecordvo为封装的vo,包含了返回的page对象
activityreceivesendrecordvo.setactivityrecordvolist(page);
总结
使用了这么长时间spring data jpa,觉得specifications巨好用,也不容易出错,也是我喜欢的编码风格,而new pageimpl<>()这种简单粗暴的方法我一般都用在查询数据关联太多表的情况,在最后直接返回,更深层次的还需要再探讨!
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。
推荐阅读
-
使用Spring Data JPA的坑点记录总结
-
Spring boot中使用Spring-data-jpa方便快捷的访问数据库(推荐)
-
spring data jpa碰到的坑
-
Spring Data数据持久化API JPA的使用
-
Spring data jpa的使用与详解(复杂动态查询及分页,排序)
-
spring data jpa 使用记录 映射相关
-
使用spring-data-jpa进行count时报错No property count found for type xxx的解决方案
-
Spring+Data+JPA持久层的使用及注意事项(一)
-
spring-data-jpa使用缓存的注意事项
-
spring data jpa碰到的坑