前言
我们在做日常开发中经常会进行数据库的操作,ORM框架可以帮助我们更便捷的进行数据的操作。SpringDataJPA就是我们经常用到的ORM框架,我们只需要定义一些实体类以及实现一些接口,它便为我们生成了一些丰富的SQL操作功能。但是如果涉及到多表动态查询, JPA 的功能就显得有些捉襟见肘了,虽然我们可以使用注解 @Query ,在这个注解中写 SQL ,但是这样我们又需要创建Model对象以及Repository接口。好在Spring可以方便的集成QueryDSL,让我们方便的实现这些功能。
QueryDSL仅仅是一个通用的查询框架,专注于通过Java API构建类型安全的SQL查询。
QueryDSL可以通过一组通用的查询API为用户构建出适合不同类型ORM框架或者是SQL的查询语句,也就是说QueryDSL是基于各种ORM框架以及SQL之上的一个通用的查询框架。
借助QueryDSL可以在任何支持的ORM框架或者SQL平台上以一种通用的API方式来构建查询。目前QueryDSL支持的平台包括JPA,JDO,SQL,Mongodb 等等。
环境准备
我们采用spirngboot作为基础框架,开发语言选择kotlin,数据库选择postgre,构建工具选择maven,引入web、jpa、QueryDSL、openapi等相关依赖。
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 https://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.7.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.bliietsdoux</groupId>
<artifactId>jpa_learn_maven</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>jpa_learn_maven</name>
<description>jpa_learn_maven</description>
<properties>
<java.version>17</java.version>
<kotlin.version>1.7.10</kotlin.version>
</properties>
<dependencies>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
<version>5.0.0</version>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>5.0.0</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<configuration>
<args>
<arg>-Xjsr305=strict</arg>
</args>
<compilerPlugins>
<plugin>spring</plugin>
<plugin>jpa</plugin>
</compilerPlugins>
</configuration>
<dependencies>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-noarg</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<configuration>
<args>
<arg>-Xjsr305=strict</arg>
</args>
<!--这个spring和jpa的插件必不可少,尤其是使用data class作entity的时候,不然首先是需要你在程序入口启动类上添加open属性,而且data class编译不会产生默认无参构造函数,即使加了no-args依赖也没用 -->
<compilerPlugins>
<plugin>spring</plugin>
<plugin>jpa</plugin>
</compilerPlugins>
</configuration>
<executions>
<execution>
<id>compile</id>
<!-- 这个phase必不可少,这里的compile阶段是处理源码,-->
<phase>process-sources</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>kapt</id>
<!-- 这个phase必不可少,这里的阶段是产生Q类,-->
<phase>generate-sources</phase>
<goals>
<goal>kapt</goal>
</goals>
<configuration>
<sourceDirs>
<sourceDir>src/main/kotlin</sourceDir>
</sourceDirs>
<annotationProcessorPaths>
<annotationProcessorPath>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl.version}</version>
<!--这个jpa也比不可少 -->
<classifier>jpa</classifier>
</annotationProcessorPath>
</annotationProcessorPaths>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-noarg</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
接下来我们做一些环境配置
做好数据配置、jpa配置
spring:
mvc:
pathmatch:
matching-strategy: ant_path_matcher
datasource:
password: 123456
url: jdbc:postgresql://localhost:5432/daily
username: postgres
jpa:
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
format_sql: true
logging:
level:
org.hibernate.type.descriptor.sql.BasicBinder: trace
项目开发
项目整体结构如下
openapi的配置bean
我们先要做一下openapi的配置,创建一个config类
Entity
我们再创建一个实体类 User
Repository
因为我们是需要用到Dsl进行查询所以需要我们的Repository接口实现QuerydslPredicateExecutor
接口
Service
这里注入EntityManager
对象是因为我们后面要通过JPAQueryFactory
直接进行查询,而不通过Repository
的接口
Controller
我们这里先定义个UserController
QueryDSL对象
我们想要在代码中使用到QueryDSL对象,首先需要先编译下对象。它跟lombok一样会在编译期给我们生成一些对象,所以我们想要用到这些对象及方法需要先编译下项目。
它会在target目录下为我们生成这么一个类
通过Repository对象查询
我们先构建这么一个场景,前端传过来条件查询,然后我们通过Usr对象接受查询条件,对于非空字段进行条件筛选,其他的username跟nickname为模糊匹配,sex为精准匹配。
我们首先需要通过生成的QUser类来创建一个对象。然后根据查询条件构建查询表达式,查询的是所有字段。params.isNotNull.or(params.isNull)
相当于我们平时查询经常用到的 where 1=1
,然后再根据具体的需求构建表达式。最后调用repository.findAll()方法查询结果
再简单的在controller中开一个接口来测试一下
我们先看一下表中数据情况:
打开openapi然后调用接口:
可以看到我们已经成功根据我们的需求查询到了对应的结果
然后我们在后台看一下打印的sql语句,因为我们这里只有sex这个参数有值,所以为我们生成的sql也只有这个字段的筛选条件。
通过JPAQueryFactory查询
我们可以Repository的查询接口在其中传入查询条件这样的方式来查询,但是这种方式查询的是所有字段并且表也是Repository所对应的表,如果我们想更自由的查询可以通过JPAQueryFactory
来进行。
我们首先构建一个JPAQueryFactory
对象跟QUser
对象,这样我们就可以指定查询的字段跟表进行查询。但是他查询的结果是一个Tuple
对象我们要进行map一下变成我们需要的User对象
简单的创建接口测试一下
可以看到只返回了部分字段的结果
再查看一下后台的sql语句,确实只用到了部分的字段进行查询
后记
其实相较于JPA来说我更喜欢MyBatisPlus,究其原因是因为它既可以像JPA那样为我们提供了开箱即用的简单查询方法,又可以方便我们自己写SQL。但是SpringData为我们抽象了一层统一的api,不仅是对于关系型数据库mysql、postgre等,还有非关系型数据库如redis、mogodb、elasticsearch等。都提供了很好的支持,所有具体用什么看具体的项目。
最后吐槽一下:对于kotlin来说JPA查询时候返回的Optional太鸡肋了,kotlin可以用?
来直接判空,所以我们可为Repository接口添加扩展方法
fun<T,ID : Any> CrudRepository<T, ID>.findUserById(id:ID):T? = findById(id).orElse(null)
这样我们在调用的时候就舒服多了
标签:SpringDataJPA,kotlin,boot,Querydsl,查询,maven,org,我们 From: https://www.cnblogs.com/loveletters/p/jpa-querydsl.html