前言
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