背景
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中获得新的视角和启发,为您的数据库交互带来更多的便利和效率。
留言