Spring JPA整合QueryDSL的示例代码

前言

Spring JPA是目前比较常用的ORM解决方案,但是其对于某些场景并不是特别的方便,例如查询部分字段,联表查询,子查询等。

而接下来我会介绍与JPA形成互补,同时也是与JPA兼容得很好的框架QueryDSL

同时由于目前主流使用Spring Boot,所以本文也会基于Spring Boot来进行演示

如果对于长文无感,但是又希望了解QueryDSL可以直接查看文章最后的总结

环境信息

以下为示例的关键环境信息

  • JDK 1.8
  • maven 3.6.1
  • SpringBoot 2.2.0.RELEASE
  • IntelliJ IDEA 2019.2.3
  • lombok
  • mysql-5.7

源码地址

https://github.com/spring-based-solutions/querydsl-jpa-demo

项目整合

pom文件配置

QueryDSL本身定位就是对某些技术的补充或者说是完善,其提供了对JPAJDBCJDO等技术的支持。这里引入的是QueryDSL-JPA,需要注意一定要引入querydsl代码生成器插件。

  <properties>
    <java.version>1.8</java.version>
    <querydsl.version>4.2.1</querydsl.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <!--使用版本较老的mysql驱动包,用于连接mysql-5.7-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.48</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-configuration-processor</artifactId>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
      <exclusions>
        <exclusion>
          <groupId>org.junit.vintage</groupId>
          <artifactId>junit-vintage-engine</artifactId>
        </exclusion>
      </exclusions>
    </dependency>

    <!--引入querydsl-jpa依赖-->
    <dependency>
      <groupId>com.querydsl</groupId>
      <artifactId>querydsl-jpa</artifactId>
      <version>${querydsl.version}</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
      <!--引入querydsl代码生成器插件-->
      <plugin>
        <groupId>com.mysema.maven</groupId>
        <artifactId>apt-maven-plugin</artifactId>
        <version>1.1.3</version>
        <dependencies>
          <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-apt</artifactId>
            <version>${querydsl.version}</version>
          </dependency>
        </dependencies>
        <executions>
          <!--设置插件生效的maven生命周期-->
          <execution>
            <goals>
              <goal>process</goal>
            </goals>
            <configuration>
              <!--配置生成文件的目录-->
              <outputDirectory>src/generated-sources/java/</outputDirectory>
              <processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

application配置文件

spring:
 datasource:
  ## 数据库相关配置
  url: jdbc:mysql://127.0.0.1:3306/example?useSSL=false
  username: root
  password: root
  driver-class-name: com.mysql.jdbc.Driver # 指定驱动类
 jpa:
  hibernate:
   ddl-auto: update # 自动创建表以及更新表结构,生产环境慎用
  show-sql: true # 打印执行的SQL

配置类

由于QueryDSL不提供starter,所以需要自行准备一个配置类,代码如下所示

import com.querydsl.jpa.impl.JPAQueryFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

/**
 * QueryDSL配置类
 * @author Null
 * @date 2019-10-24
 */
@Configuration
public class QuerydslConfig {

  @Autowired
  @PersistenceContext
  private EntityManager entityManager;

  @Bean
  public JPAQueryFactory queryFactory(){
    return new JPAQueryFactory(entityManager);
  }

}

启动类

启动类很简单,只需要使用@SpringBootApplication即可

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class QuerydslJpaDemoApplication {

  public static void main(String[] args) {
    SpringApplication.run(QuerydslJpaDemoApplication.class, args);
  }
}

实体类

主要有讲师和课程,每个课程都有一个讲师,每个讲师有多个课程,即讲师与课程的关系为一对多

课程

import lombok.Data;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

/**
 * 课程,一个课程对应一个讲师
 * @author Null
 * @date 2019-10-24
 */
@Data
@Entity
public class Course {
  /**
   * 课程ID
   */
  @Id
  @GeneratedValue(strategy= GenerationType.IDENTITY)
  private Long id;
  /**
   * 课程名称
   */
  private String name;
  /**
   * 对应讲师的ID
   */
  private Long lecturerId;
}

讲师

import lombok.Data;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

/**
 * 讲师,一个讲师有多个课程
 * @author Null
 * @date 2019-10-24
 */
@Data
@Entity
public class Lecturer {
  /**
   * 讲师ID
   */
  @Id
  @GeneratedValue(strategy= GenerationType.IDENTITY)
  private Long id;
  /**
   * 讲师名字
   */
  private String name;
  /**
   * 性别,true(1)为男性,false(0)为女性
   */
  private Boolean sex;
}

Repository接口

如果要使用QuerDSL需要Repository接口除了继承JpaRepository接口(此接口为Spring-JPA提供的接口)外,还需要继承QuerydslPredicateExecutor接口。关键示例如下:

课程Repository

import com.example.querydsl.jpa.entity.Course;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;

/**
 * 课程Repository
 *
 * @author Null
 * @date 2019-10-24
 */
public interface CourseRepository extends
    JpaRepository<Course, Integer>,
    QuerydslPredicateExecutor<Course> {
}

讲师Repository

import com.example.querydsl.jpa.entity.Lecturer;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;

/**
 * 讲师Repository
 * @author Null
 * @date 2019-10-24
 */
public interface LecturerRepository extends
    JpaRepository<Lecturer,Integer>,
    QuerydslPredicateExecutor<Lecturer> {
}

代码生成

前面配置QueryDSL代码生成器就是用于这一步,==每次实体类有变更最好重复执行本步骤重新生成新的代码==。由于个人习惯使用IDEA,所以以IDEA作为演示。

双击下图内容即可生成代码了,

然后就会在src/generated-sources目录可以看到生成的代码,包名与实体包名一致,但是类名为Q开头的文件

上一步的截图我们可以看到其实生成的代码被IDEA识别为普通文件了,所以我们需要标记src/generated-sources/java目录的用途,如下图所示

标记后,效果如下,可以看到代码被正确识别了

到了这一步其实已经完成整合了,下面就开始验证是否正确整合以及展示QueryDSL的优势了

验证整合与演示

下面我会使用单元测试来验证QueryDSL是否正确整合以及演示一下QueryDSL的优势

单元测试类

这里主要是单元测试类的关键内容,需要注意@BeforeEachJunit5的注解,表示每个单元测试用例执行前会执行的方法其实对应Junit4@Before

/**
 * @SpringBootTest 默认不支持事务且自动回滚
 * 使用@Transactional 开启事务,
 * 使用@Rollback(false) 关闭自动回滚
 * @author Null
 * @date 2019-10-24
 */
@SpringBootTest
class QuerydslJpaDemoApplicationTests {

  @Autowired
  private CourseRepository courseRepository;

  @Autowired
  private LecturerRepository lecturerRepository;

  @Autowired
  private JPAQueryFactory queryFactory;

  /**
   * 初始化数据
   */
  @BeforeEach
  public void initData(){
    // 清空数据表
    courseRepository.deleteAll();
    lecturerRepository.deleteAll();

    // 初始化讲师
    Lecturer tom=new Lecturer();
    tom.setName("Tom");
    tom.setSex(true);
    lecturerRepository.save(tom);

    Lecturer marry=new Lecturer();
    marry.setName("Marry");
    marry.setSex(false);
    lecturerRepository.save(marry);

    // 初始化课程
    Course chinese=new Course();
    chinese.setName("Chinese");
    chinese.setLecturerId(tom.getId());
    courseRepository.save(chinese);

    Course physics=new Course();
    physics.setName("Physics");
    physics.setLecturerId(tom.getId());
    courseRepository.save(physics);

    Course english=new Course();
    english.setName("English");
    english.setLecturerId(marry.getId());
    courseRepository.save(english);
  }

  ...省略各个用例

}

单表模糊查询

  /**
   * 根据课程名称模糊查询课程
   */
  @Test
  public void testSelectCourseByNameLike() {
    // 组装查询条件
    QCourse qCourse = QCourse.course;
    // %要自行组装
    BooleanExpression expression = qCourse.name.like("P%");
    System.out.println(courseRepository.findAll(expression));
  }

联表查询

  /**
   * 根据讲师姓名查课程
   */
  @Test
  public void testSelectCourseByLecturerName(){
    QCourse qCourse = QCourse.course;
    QLecturer qLecturer = QLecturer.lecturer;
    // 这里包含了组装查询条件和执行查询的逻辑,组装好条件后记得执行fetch()
    List<Course> courses=queryFactory.select(qCourse)
        .from(qCourse)
        .leftJoin(qLecturer)
        .on(qCourse.lecturerId.eq(qLecturer.id))
        .where(qLecturer.name.eq("Tom"))
        .fetch();
    System.out.println(courses);
  }

更新

  /**
   * 根据姓名更新讲师性别<br/>
   * 使用@Transactional开启事务<br/>
   * 使用@Rollback(false)关闭自动回滚<br/>
   */
  @Test
  @Transactional
  @Rollback(false)
  public void testUpdateLecturerSexByName(){
    QLecturer qLecturer = QLecturer.lecturer;
    // 更新Tom的性别为女性,返回的是影响记录条数
    long num=queryFactory.update(qLecturer)
        .set(qLecturer.sex,false)
        .where(qLecturer.name.eq("Tom"))
        .execute();
    // 这里输出被更新的记录数
    System.out.println(num);
  }

删除

  /**
   * 根据根据性别删除讲师
   */
  @Test
  @Transactional
  @Rollback(false)
  public void testDeleteLecturerBySex(){
    QLecturer qLecturer = QLecturer.lecturer;
    // 删除性别为男性的讲师
    long num=queryFactory.delete(qLecturer)
        .where(qLecturer.sex.eq(true))
        .execute();
    // 输出被删除的记录数
    System.out.println(num);
  }

用例分析

从用例中可以看出其实QueryDSLAPI更加切合原生的SQL,基本上从代码上就可以看出你希望执行的SQL了。

细心的朋友会发现QueryDSL是没有insert方法,因为JPA提供的save()方法已经足够处理了。

同时要记得要组装好你的SQL后别忘记调用fetch()或者execute()方法。

总结

Spring Boot JPA整合QueryDSL的关键步骤

  • 引入依赖和插件
  • 编写配置类
  • 使用插件生成代码
  • 标记生成文件为代码
  • Repository继承QuerydslPredicateExecutor

QueryDSLAPI类似原生SQLAPI风格类似StringBuilderAPIFluent API风格)。但是不提供insert对应的操作。

QueryDSL对于复杂的SQL的支持十分友好,算是对于JPA对这块需求的补充和完善。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 详解spring boot jpa整合QueryDSL来简化复杂操作

    前言 使用过spring data jpa的同学,都很清楚,对于复杂的sql查询,处理起来还是比较复杂的,而本文中的QueryDSL就是用来简化JPA操作的. Querydsl定义了一种常用的静态类型语法,用于在持久域模型数据之上进行查询.JDO和JPA是Querydsl的主要集成技术.本文旨在介绍如何使用Querydsl与JPA组合使用.JPA的Querydsl是JPQL和Criteria查询的替代方法.QueryDSL仅仅是一个通用的查询框架,专注于通过Java API构建类型安全的SQL查

  • Spring JPA整合QueryDSL的示例代码

    前言 Spring JPA是目前比较常用的ORM解决方案,但是其对于某些场景并不是特别的方便,例如查询部分字段,联表查询,子查询等. 而接下来我会介绍与JPA形成互补,同时也是与JPA兼容得很好的框架QueryDSL. 同时由于目前主流使用Spring Boot,所以本文也会基于Spring Boot来进行演示 如果对于长文无感,但是又希望了解QueryDSL可以直接查看文章最后的总结 环境信息 以下为示例的关键环境信息 JDK 1.8 maven 3.6.1 SpringBoot 2.2.0.

  • spring boot整合Swagger2的示例代码

    Swagger 是一个规范和完整的框架,用于生成.描述.调用和可视化RESTful风格的 Web 服务.总体目标是使客户端和文件系统作为服务器以同样的速度来更新.文件的方法,参数和模型紧密集成到服务器端的代码,允许API来始终保持同步.Swagger 让部署管理和使用功能强大的API从未如此简单. 1.代码示例 1).在pom.xml文件中引入Swagger2 <dependency> <groupId>io.springfox</groupId> <artifa

  • Spring Security整合CAS的示例代码

    这里使用的是spring-security和原生的jasig cas包来进行整合,为什么没有直接使用spring提供的spring-security-cas,后面会进行解释. 配置 web.xml <filter> <filter-name>casFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-cla

  • Spring Boot整合QueryDSL的实现示例

    之前研究Jooq,今天来研究一下搭配JPA的QueryDSL吧. 简介 Querydsl是一个Java开源框架用于构建类型安全的SQL查询语句.它采用API代替拼凑字符串来构造查询语句.可跟 Hibernate 和 JPA 等框架结合使用. 新建Spring Boot项目 ...还说啥? 1. pom.xml <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <

  • springboot整合Mybatis、JPA、Redis的示例代码

    引言 在springboot 项目中,我们是用ORM 框架来操作数据库变的非常方便.下面我们分别整合mysql ,spring data jpa 以及redis .让我们感受下快车道. 我们首先创建一个springboot 项目,创建好之后,我们来一步步的实践. 使用mybatis 引入依赖: <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-

  • spring boot整合hessian的示例

    首先添加hessian依赖 <dependency> <groupId>com.caucho</groupId> <artifactId>hessian</artifactId> <version>4.0.38</version> </dependency> 服务端:HessianServer,端口号:8090 public interface HelloWorldService { String sayHel

  • Spring Boot集成Kafka的示例代码

    本文介绍了Spring Boot集成Kafka的示例代码,分享给大家,也给自己留个笔记 系统环境 使用远程服务器上搭建的kafka服务 Ubuntu 16.04 LTS kafka_2.12-0.11.0.0.tgz zookeeper-3.5.2-alpha.tar.gz 集成过程 1.创建spring boot工程,添加相关依赖: <?xml version="1.0" encoding="UTF-8"?> <project xmlns=&qu

  • SpringBoot 整合 JMSTemplate的示例代码

    1.1 添加依赖   可以手动在 SpringBoot 项目添加依赖,也可以在项目创建时选择使用 ActiveMQ 5 自动添加依赖.高版本 SpringBoot (2.0 以上) 在添加 activemq 连接池依赖启动时会报 Error creating bean with name 'xxx': Unsatisfied dependency expressed through field 'jmsTemplate'; 可以将 activemq 连接池换成 jms 连接池解决. <depen

  • SpringBoot整合SpringDataRedis的示例代码

      本文介绍下SpringBoot如何整合SpringDataRedis框架的,SpringDataRedis具体的内容在前面已经介绍过了,可自行参考. 1.创建项目添加依赖   创建SpringBoot项目,并添加如下依赖: <dependencies> <!-- springBoot 的启动器 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId

  • SpringBoot整合ShardingSphere的示例代码

    目录 一.相关依赖 二.Nacos数据源配置 三.项目配置 四.验证 概要: ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈,它由Sharding-JDBC.Sharding-Proxy和Sharding-Sidecar(计划中)这3款相互独立的产品组成. 他们均提供标准化的数据分片.分布式事务和数据库治理功能,可适用于如Java同构.异构语言.云原生等各种多样化的应用场景. 官网地址:https://shardingsphere.apache.org/ 一.相关

随机推荐