JPA多条件复杂SQL动态分页查询

概述

  ORM映射为我们带来便利的同时,也失去了较大灵活性,如果SQL较复杂,要进行动态查询,那必定是一件头疼的事情(也可能是lz还没发现好的方法),记录下自己用的三种复杂查询方式。

环境

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><!--数据库连接--><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><!-- 热启动等 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><!--Java bean 实体--><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 测试工具 --><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><!--安全框架认证--><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><!--汉字转拼音--><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

当一个SQL较为复杂时,第一个想到的就是原生的SQL语句。如果只是简单的查询,那情况还没这么糟糕

 @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);

但如果需要进行动态查询,或更改,那这个value就变得复杂了。

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代码内发出JPQL查询,就需要利用到EntityManager的响应方法了。一般执行以下流程

  1. 获取一个EntityManager实例
  2. 调用实例的方法createQuery,创建一个Query实例,如果有需要可以指定检索的最大数量和起始位置
  3. 使用Query方法getResultList执行查询,当然更新和删除操作得使用executeUpdate执行

进行一个复杂的动态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);}/**班级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,因为是从0开始的。

Criteria

这是一种规范查询是以元模型的概念为基础的,这个元模型可以是实体累,嵌入类,或者映射的父类,简单介绍几个里面用到接口。

CriteraQuery是一个特定的顶层查询对象,里面包含select,from,where,order by等各个部分,然而他只对实体类或嵌入类的标准查询起作用。

Root标准查询的根对象,根定义了实体类型,是你想要查询要获得的结果,也可以添加查询条件,结合实体管理对象得到查询的对象。

CriteriaBuilder接口用来构建CritiaQuery的构建器

 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:学生对象* @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
{
}

动态查询

    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>(){@Overridepublic Predicate toPredicate(Root<StudentEntity> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder){//page : 0 开始, limit : 默认为 10List<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必须是实体类属性与数据库对应,否则报ropertyReferenceException异常*/PageRequest page = new PageRequest(pageNumber,pageSize,Sort.Direction.ASC,"studentId");Page<StudentEntity> pages = studentDao.findAll(specification,page);return pages;}

因为这个项目应用比较简单,所以条件只有一个,如果条件较多,甚至可以定义一个专门的类去接收拼接参数,然后判断,成立就add进去。

转载一篇写得不错的文章:https://blog.csdn.net/u010775025/article/details/80497986

 

转载于:https://www.cnblogs.com/dslx/p/11474453.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/262767.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

上下文环境

##执行上下文环境 在一段JS真正运行之前浏览器已经做了一些准备工作&#xff1a; 1.变量&#xff1a;变量的申明&#xff0c;默认值为undefined&#xff1b; 2.this&#xff1a;赋值&#xff1b; 3.函数申明&#xff1a;赋值 变量&#xff1a; console.log(a) ---…

dbgrideh的功能

dbgrideh的功能 a.点标题排序&#xff1a; 1.eh的optionsEh 的dghAutoSortMarking True 2 eh的sortlocal true 3.列的title的toolbutton为true 4。eh的optionsEh 的dghMultiSortMarking True 多个字段一起排(按CTRLMouse) 5.uses加相应的驱动ehlibado/ehlibbde b.模糊过滤: …

深入A*算法

一、前言 在这里我将对A*算法的实际应用进行一定的探讨&#xff0c;并且举一个有关A*算法在最短路径搜索的例子。 二、A*算法的程序编写原理 A*算法是最好优先算法的一种。只是有一些约束条件而已。我们先来看看最好优先算法是如何编写的吧。 如图有如下的状态空间&#xff1a;…

IOS中NSUserDefaults的用法

2019独角兽企业重金招聘Python工程师标准>>> IOS中NSUserDefaults的用法&#xff08;轻量级本地数据存储&#xff09; 分类&#xff1a; IOS开发 Object&#xff0d;C编程语言2012-09-09 10:58 65223人阅读 评论(13) 收藏 举报 存储iosfloatinterfaceintegerdate NS…

如何做好产品经理一:你们是傻的吗?

如果你想做一个坏的产品经理, 就把那些和你意见不同的人都当作傻子。是的&#xff0c;你重复了好几遍你的看法&#xff0c;但他们就是不懂&#xff0c;估计他们永远都不会懂。这些人在想什么&#xff0c;都是傻的吗&#xff1f;既然你无法让这些傻子理解你说的话&#xff0c;干…

【Oracle 学习笔记】Day 1 常用函数整理(转换、DeCode),表的外键

select Convert(varchar,Convert(money,TaxExValue),1) from A--Result 2,794.87 58,119.66 1,367.52 对于SQL Server来说&#xff0c;进行金额的转换&#xff0c;可以按照上面的操作那样&#xff0c;会自动将金额处理为两位小数&#xff0c;并用逗号分隔小数点前面的数字。 当…

LOJ bitset+分块 大内存毒瘤题

题面 $ solution: $ 真的没有想到可以用分块。 但是可以发现一个性质&#xff0c;每个询问只关心这个点最后一次赋值操作&#xff0c;和这个赋值操作后的所有取 $ min $ 操作。这个感觉很有用&#xff0c;但是真的很难让人想到低于 $ n\times m $ 的做法。基于 $ DAG $ 的数据结…

Web开发编程实用手册

不要被这个名字吓到。这本手册&#xff0c;真的很实用。你能猜猜它有多少页么&#xff1f;只有62页&#xff0c;比起那些砖头书来&#xff0c;这本可以说是苗条得不能再苗条了。现在卓越搞活动&#xff0c;购买电子工业出版社图书&#xff0c;凡购买专题内图书满69元&#xff0…

版本管理工具:git svn 的比较

git&#xff1a;分布式。开发者可以提交到本地&#xff0c;每个开发者机器上都是一个完整的数据库。两个开发者之间&#xff0c;可以通过打patch的方式交换文件。svn&#xff1a;集中式。所谓 git 服务器&#xff0c;是指大家约定使用同一个网址提交、更新代码。这个网址可以是…

C# 配置文件 自定義結點

1. 對於配置自定義結點&#xff0c;需要繼承ConfigurationSection類。 UrlsSection : ConfigurationSection 2. 配置文件中&#xff0c;需要如下引用&#xff1a; View Code <configSections><section name"orders" type"WebApplication4.UrlsS…

uni-app 手指左右滑动实现翻页效果

首先给页面添加 touch 事件 <view class"text-area" touchstart"start" touchend"end"></view> 然后定义一个合理区间进行判断,用户当前是上下滑动看书还是左右滑动变换章节. start(e){this.startData.clientXe.changedTouches[0].c…

sizeof 再遇

看下面程序片段&#xff1a; #include <stdio.h>int main(){int a255;printf("%d\n", sizeof(a));printf("%d\n", a);return 0;}结果&#xff1a; 4255 这个是我们已经熟知的&#xff1a;sizeof是编译期求值&#xff0c;所以sizeof中表达式根本不计算…

mybatis错误之配置文件属性配置问题

在mybatis的配置文件SqlMapConfig.xml中&#xff0c;可以在开始的地方先加载一个properties节点&#xff0c;用来定义属性变量。 1 <!-- 加载属性文件 --> 2 <properties resource"db.properties"> 3 <!--properties中还可以配置一些属性…

weblogic环境搭建

官方指导文档说明&#xff1a;http://docs.oracle.com/cd/E24329_01/web.1211/e24493/getst.htm#autoId12配置管理员用户名和口令&#xff1a;名称&#xff1a;weblogic密码&#xff1a;weblogic域名&#xff1a;sniper说明&#xff1a;This user is the default administrator…

20个方法让你摆脱坏习惯

原文&#xff1a;20 Tricks to Nuke a Bad Habit翻译&#xff1a;弥缝&#xff08;褪墨&#xff09; 你的生活正在被坏习惯不断地侵蚀&#xff1f;我从几年前开始改变我的习惯&#xff0c;现在我已经养成以素食为主的用餐、每天锻炼身体、每天写新文章、早起等等好习惯&#xf…

Stream流思想和常用方法

一、IO流用于读写&#xff1b;Stream流用于处理数组和集合数据&#xff1b; 1、传统集合遍历&#xff1a; 2、使用Stream流的方式过滤&#xff1a; 其中&#xff0c;链式编程&#xff08;返回值就是对象自己&#xff09;中&#xff0c;filter使用的是Predicate函数式接口&#…

九九乘法表的C语言实现

#include "stdio.h"int main(){int i,j,a;printf("九九乘法表:\n");for(i1;i<10;ii1){for(j1;j<i;jj1){ai*j;printf("%5d*%d%d",i,j,a);if(ij)printf("\n");}}return 0; }转载于:https://blog.51cto.com/xmwen1/1697355

关于各种JOIN连接的解释说明【原创】

INNER JOIN的连接原理&#xff1a;1.从左表里取出第一行2.按照ON条件查找右表里的每一行3.找出匹配的行&#xff08;包括重复的行&#xff09;放在结果集里&#xff0c;不匹配的行则放弃。4.从左表里取出第二行5.重复步骤2-36.从左表里取出第三行7............. LEFT JOIN的连接…

Stream流方法引用

一、对象存在&#xff0c;方法也存在&#xff0c;双冒号引用 1、方法引用的概念&#xff1a; 使用实例&#xff1a; 1.1先定义i一个函数式接口&#xff1a; 1.2定义一个入参参数列表有函数式接口的方法&#xff1a; 1.3调用这个入参有函数式接口的方法&#xff1a; lambda表达式…

九度OJ 1054:字符串内排序

题目地址&#xff1a;http://ac.jobdu.com/problem.php?id1054题目描述&#xff1a; 输入一个字符串&#xff0c;长度小于等于200&#xff0c;然后将输出按字符顺序升序排序后的字符串。 输入&#xff1a; 测试数据有多组&#xff0c;输入字符串。 输出&#xff1a; 对于每组输…