JPA多條件復(fù)雜SQL動(dòng)態(tài)分頁(yè)查詢功能
概述
ORM映射為我們帶來(lái)便利的同時(shí),也失去了較大靈活性,如果SQL較復(fù)雜,要進(jìn)行動(dòng)態(tài)查詢,那必定是一件頭疼的事情(也可能是lz還沒發(fā)現(xiàn)好的方法),記錄下自己用的三種復(fù)雜查詢方式。
環(huán)境
springBoot
IDEA2017.3.4
JDK8
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.xmlxy</groupId>
<artifactId>seasgame</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>seasgame</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--數(shù)據(jù)庫(kù)連接-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- 熱啟動(dòng)等 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!--Java bean 實(shí)體-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!--swagger2 API 測(cè)試工具 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!--安全框架認(rèn)證-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.2.2</version>
<classifier>jdk15</classifier>
</dependency>
<!--漢字轉(zhuǎn)拼音-->
<dependency>
<groupId>com.belerweb</groupId>
<artifactId>pinyin4j</artifactId>
<version>2.5.1</version>
</dependency>
<!-- thymeleaf模板 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
移除嵌入式tomcat插件
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<packaging>war</packaging>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
<finalName>seasgame</finalName>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<encoding>${project.build.sourceEncoding}</encoding>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<testFailureIgnore>true</testFailureIgnore>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
@Query
當(dāng)一個(gè)SQL較為復(fù)雜時(shí),第一個(gè)想到的就是原生的SQL語(yǔ)句。如果只是簡(jiǎn)單的查詢,那情況還沒這么糟糕
@Query(value = " SELECT IFNULL(sum(right_num),0) sumRight FROM t_record WHERE record_owner_id = ?1 AND responder_no = ?2 ",nativeQuery = true) Map<String,Object> sumRightNum(int studentId,int responderNo);
但如果需要進(jìn)行動(dòng)態(tài)查詢,或更改,那這個(gè)value就變得復(fù)雜了。
package com.xmlxy.seasgame.dao;
import com.xmlxy.seasgame.entity.ScoreEntity;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
*
* Description:
* @author hwc
* @date 2019/9/5
* @return
*/
public interface ScoreDao extends CrudRepository<ScoreEntity,Integer>
{
/**
*
* Description:
*@param scoreEntity
* @author hwc
* @date 2019/9/6
*/
@Transactional(rollbackFor = Exception.class)
@Modifying
@Query(value = "UPDATE t_score t SET " +
"t.responder_no = CASE WHEN :#{#scoreEntity.responderNo} IS NULL THEN t.responder_no ELSE :#{#scoreEntity.responderNo} END," +
"t.max_level = CASE WHEN :#{#scoreEntity.maxLevel} IS NULL THEN t.max_level ELSE :#{#scoreEntity.maxLevel} END," +
"t.right_num = CASE WHEN :#{#scoreEntity.rightNum} IS NULL THEN t.right_num ELSE :#{#scoreEntity.rightNum} END," +
"t.use_time = CASE WHEN :#{#scoreEntity.userTime} IS NULL THEN t.use_time ELSE :#{#scoreEntity.userTime} END WHERE student_id = :#{#scoreEntity.getStudentId()}",nativeQuery = true)
void updateScore(@Param("scoreEntity") ScoreEntity scoreEntity);
}
JPQL
如果Java代碼內(nèi)發(fā)出JPQL查詢,就需要利用到EntityManager的響應(yīng)方法了。一般執(zhí)行以下流程
獲取一個(gè)EntityManager實(shí)例
調(diào)用實(shí)例的方法createQuery,創(chuàng)建一個(gè)Query實(shí)例,如果有需要可以指定檢索的最大數(shù)量和起始位置
使用Query方法getResultList執(zhí)行查詢,當(dāng)然更新和刪除操作得使用executeUpdate執(zhí)行
進(jìn)行一個(gè)復(fù)雜的動(dòng)態(tài)SQL查詢
public Page<RankEntity> getScoreByRank(int gradeId,int classId,Pageable pageable)
{
StringBuilder countSelectSql = new StringBuilder("");
countSelectSql.append(" SELECT COUNT(*) ");
countSelectSql.append(" FROM ");
countSelectSql.append(" t_score s, ");
countSelectSql.append(" t_student st ");
countSelectSql.append(" WHERE ");
countSelectSql.append(" s.student_id = st.student_id ");
StringBuilder selectSql = new StringBuilder();
selectSql.append(" SELECT s.student_id,st.real_name,st.student_class,s.max_level,s.use_time,s.right_num ");
selectSql.append(" FROM t_score s ");
selectSql.append(" JOIN t_student st ON s.student_id = st.student_id ");
selectSql.append(" WHERE 1 = 1 ");
Map<String,Object> params = new HashMap<>();
StringBuilder whereSql = new StringBuilder();
if (gradeId != -1)
{
whereSql.append(" AND st.student_grade = :student_grade ");
params.put("student_grade",gradeId);
}
/**班級(jí)ID*/
if (classId != -1)
{
whereSql.append(" AND st.student_class = :classId ");
params.put("classId",classId);
}
String orderSql = " ORDER BY s.max_level DESC,s.use_time,s.right_num ASC ";
String countSql = new StringBuilder().append(countSelectSql).append(whereSql).toString();
Query countQuery = entityManager.createNativeQuery(countSql);
for (Map.Entry<String,Object> entry : params.entrySet())
{
countQuery.setParameter(entry.getKey(),entry.getValue());
}
BigInteger totalCount = (BigInteger)countQuery.getSingleResult();
String querySql = new StringBuilder().append(selectSql).append(whereSql).append(orderSql).toString();
Query query = entityManager.createNativeQuery(querySql,RankEntity.class);
for (Map.Entry<String,Object> entry:params.entrySet())
{
query.setParameter(entry.getKey(),entry.getValue());
}
query.setFirstResult((int) pageable.getOffset());
query.setMaxResults(pageable.getPageSize());
List<RankEntity> rankEntities = query.getResultList();
Page<RankEntity> page = new PageImpl<>(rankEntities,pageable,totalCount.longValue());
return page;
}
注意:如果沒有重新定義Pageable那么pageNumber必須減1,因?yàn)槭菑?開始的。
Criteria
這是一種規(guī)范查詢是以元模型的概念為基礎(chǔ)的,這個(gè)元模型可以是實(shí)體累,嵌入類,或者映射的父類,簡(jiǎn)單介紹幾個(gè)里面用到接口。
CriteraQuery是一個(gè)特定的頂層查詢對(duì)象,里面包含select,from,where,order by等各個(gè)部分,然而他只對(duì)實(shí)體類或嵌入類的標(biāo)準(zhǔn)查詢起作用。
Root標(biāo)準(zhǔn)查詢的根對(duì)象,根定義了實(shí)體類型,是你想要查詢要獲得的結(jié)果,也可以添加查詢條件,結(jié)合實(shí)體管理對(duì)象得到查詢的對(duì)象。
CriteriaBuilder接口用來(lái)構(gòu)建CritiaQuery的構(gòu)建器
StudentEntity類
package com.xmlxy.seasgame.entity;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import javax.persistence.*;
import javax.print.attribute.standard.MediaSize;
import java.io.Serializable;
/**
*
* Description:學(xué)生對(duì)象
* @param
* @author hwc
* @date 2019/8/8
*/
@Entity
@Table(name = "t_base_student")
@ApiModel
@Data
public class StudentEntity implements Serializable
{
private static final long serialVersionUID = 546L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "student_id")
private Integer studentId;
@Column(name = "student_grade")
private Integer studentGrade;
@Column(name = "student_class")
private Integer studentClass;
@Column(name = "address")
private String address;
@Column(name = "telephone")
private Integer telephone;
@Column(name = "real_name")
private String realName;
@Column(name = "id_number")
private String idNumber;
@Column(name = "study_id")
private String studyId;
@Column(name = "is_delete")
private int isDelete;
@Column(name = "uuid")
private String uuid;
}
dao層
public interface StudentDao extends JpaRepository<StudentEntity,Integer>,JpaSpecificationExecutor
{
}
動(dòng)態(tài)查詢
public Page<StudentEntity> getTeacherClassStudent(int pageNumber,int pageSize,int gradeId, int classId,String keyword)
{
pageNumber = pageNumber < 0 ? 0 : pageNumber;
pageSize = pageSize < 0 ? 10 : pageSize;
Specification<StudentEntity> specification = new Specification<StudentEntity>()
{
@Override
public Predicate toPredicate(Root<StudentEntity> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder)
{
//page : 0 開始, limit : 默認(rèn)為 10
List<Predicate> predicates = new ArrayList<>();
predicates.add(criteriaBuilder.equal(root.get("studentGrade"),gradeId));
predicates.add(criteriaBuilder.equal(root.get("studentClass"),classId));
if (!Constant.isEmptyString(keyword))
{
predicates.add(criteriaBuilder.like(root.get("realName").as(String.class),"%" + keyword + "%"));
}
return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
}
};
/*studentId必須是實(shí)體類屬性與數(shù)據(jù)庫(kù)對(duì)應(yīng),否則報(bào)ropertyReferenceException異常*/
PageRequest page = new PageRequest(pageNumber,pageSize,Sort.Direction.ASC,"studentId");
Page<StudentEntity> pages = studentDao.findAll(specification,page);
return pages;
}
因?yàn)檫@個(gè)項(xiàng)目應(yīng)用比較簡(jiǎn)單,所以條件只有一個(gè),如果條件較多,甚至可以定義一個(gè)專門的類去接收拼接參數(shù),然后判
斷,成立就add進(jìn)去。
總結(jié)
以上所述是小編給大家介紹的JPA多條件復(fù)雜SQL動(dòng)態(tài)分頁(yè)查詢功能,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
如果你覺得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!
相關(guān)文章
maven打包zip包含bin下啟動(dòng)腳本的完整代碼
這篇文章主要介紹了maven打包zip包含bin下啟動(dòng)腳本,本文給大家講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-10-10
SpringBoot使用WebSocket實(shí)現(xiàn)前后端交互的操作方法
springboot使用websocket有兩種方式,一種是實(shí)現(xiàn)簡(jiǎn)單的websocket,另外一種是實(shí)現(xiàn)STOMP協(xié)議,本篇講述如何使用springboot實(shí)現(xiàn)簡(jiǎn)單的websocket,需要的朋友可以參考下2022-04-04
java多線程數(shù)據(jù)分頁(yè)處理實(shí)例講解
在本篇內(nèi)容里小編給大家分享了一篇關(guān)于java多線程數(shù)據(jù)分頁(yè)處理實(shí)例講解內(nèi)容,有興趣的朋友們可以學(xué)習(xí)下。2021-01-01
Java實(shí)現(xiàn)計(jì)網(wǎng)循環(huán)冗余檢驗(yàn)算法的方法示例
這篇文章主要給大家介紹了關(guān)于Java實(shí)現(xiàn)計(jì)網(wǎng)循環(huán)冗余檢驗(yàn)算法的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
Java實(shí)現(xiàn)消消樂(lè)中的消除功能
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)消消樂(lè)中的消除功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07
Springboot使用RestTemplate調(diào)用第三方接口的操作代碼
這篇文章主要介紹了Springboot使用RestTemplate調(diào)用第三方接口,我只演示了最常使用的請(qǐng)求方式get、post的簡(jiǎn)單使用方法,當(dāng)然RestTemplate的功能還有很多,感興趣的朋友可以參考RestTemplate源碼2022-12-12

