使用Spring Data JPA的坑點記錄總結
前言
Spring-data-jpa的基本介紹:JPA誕生的緣由是為了整合第三方ORM框架,建立一種標準的方式,百度百科說是JDK為了實現ORM的天下歸一,目前也是在按照這個方向發(fā)展,但是還沒能完全實現。在ORM框架中,Hibernate是一支很大的部隊,使用很廣泛,也很方便,能力也很強,同時Hibernate也是和JPA整合的比較良好,我們可以認為JPA是標準,事實上也是,JPA幾乎都是接口,實現都是Hibernate在做,宏觀上面看,在JPA的統(tǒng)一之下Hibernate很良好的運行。
最近在使用Springboot 以及Spring data jpa ,使用jpa可以讓我更方便的操作數據庫,但在使用中也遇到了不少的坑,下面這篇文章就來記錄下,下面話不多說了,來一起看看詳細的介紹吧。
場景:
動態(tài)查詢,分頁查詢,根據傳入不同的狀態(tài),分別查詢不同數據表,并且在傳入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先根據查詢條件動態(tài)查詢并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<>()這種簡單粗暴的方法我一般都用在查詢數據關聯太多表的情況,在最后直接返回,更深層次的還需要再探討!
好了,以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

