内容纲要

背景

QueryDSL是一个强大的查询构建库,它允许在Java环境中以类型安全的方式构建查询。它主要用于与关系型数据库进行交互,特别是使用JPA和SQL时。QueryDSL的语法与SQL极为相似,所以可读性很好。查询出数据后可以直接将其映射为Java类型,使得查询构建更加直观和易于维护。

在传统的查询构建中,我们经常使用字符串拼接的方式来构建查询条件,这种方式容易出错且不易于维护。而QueryDSL通过使用类型安全的构建器模式,可以避免SQL注入攻击,同时提高代码的可读性和可维护性。

总之,QueryDSL是一个非常有用的工具,可以帮助我们更好地与数据库进行交互,提高代码质量和安全性。在本篇博客中,我们将详细介绍如何使用QueryDSL来构建查询,以及如何结合其他技术进行更高级的应用。

QueryDSL官方网站:https://querydsl.com/

使用方式

环境

  • Java
  • Spring
  • Mysql
  • JPA
  • Gradle

引入依赖

implementation 'com.querydsl:querydsl-jpa:4.4.0'
//启用注解需要用到annotationProcessor
annotationProcessor 'com.querydsl:querydsl-apt:4.4.0:jpa'

数据准备

定义Java类

下面定义了2个Java类,分别是用户类和成绩类。用户类存储用户的姓名、性别和班级。成绩类存储用户ID、成绩类型(MATH,ENGLISH,SCIENCE)、成绩和创建时间。在这个示例中我们模拟有一些学生,每个学生都会有一些科目的成绩,以此进行单表查询和多表联查。

@Entity
@NoArgsConstructor
@AllArgsConstructor
@Data
@Table(name = "user")
public class UserQuery {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    @Enumerated(value = EnumType.STRING)
    private Gender gender;
    private Integer classNo;
}
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Data
@Table(name = "score")
public class ScoreQuery {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private Long userId;
    @Enumerated(value = EnumType.STRING)
    private CourseType type;
    private Integer score;
    private LocalDateTime createdTime;
}

定义表结构

create table user
(
    id bigint auto_increment,
    name varchar(20) not null,
    gender varchar(20) not null,
    class_no int not null,
    constraint user_pk
        primary key (id)
);
create table score
(
    id bigint auto_increment,
    userId bigint not null,
    type varchar(20) not null,
    score int not null,
    created_time datetime default now() not null,
    constraint score_pk
        primary key (id)
);

配置JPAQueryFactory

使用QueryDSL的功能时需要使用JPAQueryFactory,而JPAQueryFactory在这里依赖使用EntityManager。所以需要注入如下的配置类,使得Spring自动帮我们注入EntityManager并且管理JPAQueryFactory。

@Configuration
public class JpaQueryFactoryConfig {
    @Bean
    public JPAQueryFactory jpaQueryFactory(EntityManager entityManager) {
        return new JPAQueryFactory(entityManager);
    }
}   

compile获得Q类

这是QueryDSL能提供给开发者的,当一个Java类注解了@Entity后,运行Gradle的Compile时就会生成一个Q类,这就是在后续的查询中需要用到的Q类。

单表查询

@Service
@RequiredArgsConstructor
public class UserQueryApplication {
    private final JPAQueryFactory jpaQueryFactory;

    public List<UserQuery> getUsers(String name, Gender gender, Integer classNo) {
        BooleanBuilder builder = new BooleanBuilder();
        if (Objects.nonNull(name)) {
            builder.and(userQuery.name.like(name));
        }
        if (Objects.nonNull(gender)) {
            builder.and(userQuery.gender.eq(gender));
        }
        if (Objects.nonNull(classNo)) {
            builder.and(userQuery.classNo.eq(classNo));
        }
        return jpaQueryFactory.selectFrom(userQuery)
                .where(builder)
                .fetch();
    }
}

在UserQueryApplication中定义了查询user的方法,getUsers可以根据传入的参数查询所有符合条件的user表数据。其中姓名的搜索用了模糊搜索,而性别和班级的查询是精确匹配。

多表联查

如下是查询所有用户的方法,查询出的用户会根据所有成绩的总和进行排序。(一个简易的排行榜功能)

@Service
@RequiredArgsConstructor
public class UserQueryApplication {
    private final JPAQueryFactory jpaQueryFactory;

    public List<UserQuery> getUsersWithScore() {
        return jpaQueryFactory.selectFrom(userQuery)
                .leftJoin(scoreQuery)
                .on(userQuery.id.eq(scoreQuery.userId))
                .orderBy(scoreQuery.score.sum().desc())
                .fetch();
    }
}

经过上述对单表查询和多表联查的简单示例的探讨,我们可以清晰地看到QueryDSL的语法与MySQL之间存在着深厚的相似性。这无疑为已经熟悉MySQL的用户提供了一个无缝的迁移体验。而除了这些基本的查询操作,QueryDSL同样支持MySQL中常见的排序、分类(GROUP BY)、IN查询以及区间查询(BETWEEN)等操作。

然而,这仅仅是冰山一角。QueryDSL的强大之处在于其对于复杂查询的强大支持,以及与Spring Data JPA的无缝集成,使得我们可以在JPA的实体上定义查询接口,并通过注解或方法名来构建查询。

对于那些希望深入了解QueryDSL各种使用场景的朋友们,我强烈建议您亲自尝试并探索其各种可能性。无论是初学者还是资深开发者,都可以从QueryDSL中获得新的视角和启发,为您的数据库交互带来更多的便利和效率。

最后修改日期: 2024年2月5日

留言

撰写回覆或留言

发布留言必须填写的电子邮件地址不会公开。