前言
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内,返回数据包括了分页数据
1
2
3
4
5
6
|
@ApiModelProperty ( "记录" ) private Page<ActivityRecordVO> activityRecordVOList; @ApiModelProperty ( "数量" ) private Integer num = 0 ; @ApiModelProperty ( "金额" ) private BigDecimal totalMoney = BigDecimal.valueOf( 0 ); |
错误运用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
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()); } } |
1
2
|
activityReceiveSendRecordVO.setActivityRecordVOList( new PageImpl<>(activityRecordVOList, pageable, activityRecordVOList.size())); |
解析:传入的pageable只在set进VO的时候,用new PageIml将List转为page对象,前端报的问题 虽然总页数、总条数均为正确,但第一页的条数是全部 ,数据异常!
正确参考做法:
采用Specifications先根据查询条件动态查询并map出相应分页对象(此块代码因需求而异),这时 findAll 传入的pageable是生效的,便会显现正确的分页信息。
代码块参考:
xxxCommonSpecUtil 是自封的specification工具类,与原生spring data jpa原生查询方法类似。
1
2
3
4
5
6
7
8
9
10
11
12
|
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对象
1
|
activityReceiveSendRecordVO.setActivityRecordVOList(page); |
总结
使用了这么长时间spring data jpa,觉得Specifications巨好用,也不容易出错,也是我喜欢的编码风格,而new PageImpl<>()这种简单粗暴的方法我一般都用在查询数据关联太多表的情况,在最后直接返回,更深层次的还需要再探讨!
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。
原文链接:http://www.jianshu.com/p/cec7005ce17c