关于 QueryDSL 配置和使用(详细)

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

关于 QueryDSL

最近写项目,使用到了 Jpa 这个 ORM 规范支持,使用注解的方式实现 Sql ,但是用过 Jpa 的同学都知道 Jpa 对于单表操作很灵活,但是对于复杂一些的 SQL 就是很不友好了,所以这个地方我们就用到了 QueryDSL 来实现复杂的 Sql(另外强行安利一波 Tk-MyBatis)

什么是 QueryDSL ?

QueryDSL仅仅是一个通用的查询框架,专注于通过 JavaAPI 构建类型安全的 Sql 查询,也可以说 QueryDSL 是基于各种 ORM 框架以及 Sql 之上的一个通用的查询框架,QueryDSL 的查询,类是于 SQL 查询,很全面只不过一个是用 SQL 一个是用代码来代替 SQL -- 不多了解 QueryDSL 的其他方面了,直接进入看配置和代码吧,毕竟博主也是刚刚接触这个查询框架,就不做过多的误导了

说一下,下面示例的环境 -- MyBatis + IDEA + JPA + QueryDSL

---------------------------------------------------- 手动分界线 ----------------------------------------------------

以下为项目操作(创建项目的操作就先省略掉了,这个应该都会,不会的可以去看博主的其他博客):

首先配置 pom.xml 更古不变的定律 T_T!! 对了在安利一个插件 lombok,配合 QueryDSL 可能会更好

<!-- QueryDSL 相关依赖 -->
<dependency>
    <groupId>com.querydsl</groupId>
    <artifactId>querydsl-jpa</artifactId>
</dependency>
<dependency>
    <groupId>com.querydsl</groupId>
    <artifactId>querydsl-apt</artifactId>
    <scope>provided</scope>
</dependency>
<!-- lombok 相关依赖 -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.10</version>
    <scope>provided</scope>
</dependency>
复制代码

Ps:lombok 可以已注解的方式来对代码进行简化,省去了 get 和 set 方法,至于怎么使用 lombok ,先看本文示例吧

配置 application.properties 文件

server.port=8080
server.servlet.context-path=/
server.tomcat.uri-encoding=utf-8
###添加 MySQL 数据库配置
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/boot_test?serverTimezone=UTC&characterEncoding=UTF-8&useUnicode=true
###用户名
spring.datasource.username=xxx
###密码
spring.datasource.password=xxx
###驱动
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#是否自动生/更新成表,根据什么策略
spring.jpa.hibernate.ddl-auto=update
#JPA配置
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.properties.hibernate.legacy_limit_handler=true
#是否展示sql
spring.jpa.show-sql= true
复制代码

创建 entiy 层,因为要先创建完实体类才可以去生成 QueryDSL

package com.cs.querydsl.model;

import lombok.Data;
import org.hibernate.annotations.GenericGenerator;

import javax.persistence.*;

/**
 * @ClassName:User
 * @Description:TODO User 实体类
 * @Author LinLuoChen
 * @Date 2019/7/10/14:02
 * @Version V1.0
 **/

@Data // lombok 工具省去了 GET SET 方法
@Entity // 声明这个是一个实体类
@Table(name="user") // 对应的数据库的那个表
public class User {

    /**
     * @Description ID
     * @Author LinLuoChen
     * @Date  10:44
     **/
    @Id
    @GenericGenerator(name="id", strategy="uuid") // 这里我们的 ID 用的是 UUID
    @GeneratedValue(generator="id")
    private Integer id;

    /**
     * @Description 姓名
     * @Author LinLuoChen
     * @Date  10:44
     **/
    @Column(name = "name")
    private String name;

    /**
     * @Description 密码
     * @Author LinLuoChen
     * @Date  10:44
     **/
    @Column(name = "password")
    private String password;
}
复制代码

然后生成我们的 Q实体类,第一步点击右侧 Maven 然后选择第一个文件夹,双击 compile 它会自动运行,运行成功后会生成一个 QUser 的实体类 ,因为我们的实体类叫做 User 他是根据我们实体类来生成的

开始编写 Dao 层,引入JPA 的接口 -- !!重要 !!!

package com.cs.querydsl.dao;

import com.cs.querydsl.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.PagingAndSortingRepository;

/**
 * @ClassName:UserDao
 * @Description:TODO 用来继承 Jpa 接口
 * @Author LinLuoChen
 * @Date 2019/7/10/14:06
 * @Version V1.0
 **/
public interface UserDao extends JpaRepository<User, String>, JpaSpecificationExecutor<User>, PagingAndSortingRepository<User, String> {
    // -----
}
复制代码

这里我们省略 Service 层 直接看 Impl 接口实现类,这里就先写一个单表查询进行测试

package com.cs.querydsl.service.impl;

import com.cs.querydsl.dao.UserDao;
import com.cs.querydsl.model.QUser;
import com.cs.querydsl.model.User;
import com.cs.querydsl.service.UserService;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.thymeleaf.util.StringUtils;

import javax.annotation.PostConstruct;
import javax.persistence.EntityManager;
import java.util.List;

/**
 * @ClassName:UserServiceImpl
 * @Description:TODO 接口实现类
 * @Author LinLuoChen
 * @Date 2019/7/10/14:09
 * @Version V1.0
 **/
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    UserDao userDao;

    @Autowired
    private EntityManager entityManager;

    //查询工厂实体
    private JPAQueryFactory queryFactory;

    //实例化控制器完成后执行该方法实例化JPAQueryFactory
    @PostConstruct
    public void initFactory()
    {
        queryFactory = new JPAQueryFactory(entityManager);
    }

    /**
     * @Description 查询全部
     * @Author LinLuoChen
     * @Date  10:53
     * @return java.util.List<com.cs.querydsl.model.User>
     **/
    @Override
    public List<User> findAll(User user) {
        // 使用 QueryDSL 进行查询
        QUser qUser = QUser.user;
        // 定于获取条件
        BooleanBuilder booleanBuilder = new BooleanBuilder();
        // 要查询的条件
        if(!StringUtils.isEmpty(user.getName())){
            // 放入要查询的条件信息
            booleanBuilder.and(qUser.name.contains(user.getName()));
        }
        // queryFactory 是上方定义的工厂实体 
        // select(生成的实体类的字段).from(生成实体类的名称).where(上方要查询的条件).orderBy(排序).fetch()进行查询
        return queryFactory.select(qUser)
                .from(qUser)
                .where(booleanBuilder)
                .orderBy(qUser.name.desc())
                .fetch();
    }
}
复制代码

我们直接写一个测试类进行测试

package com.cs.querydsl;

import com.cs.querydsl.model.User;
import com.cs.querydsl.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class QuerydslApplicationTests {

    @Autowired
    UserService userService;

    @Test
    public void contextLoads() {
    }

    /**
     * @Description 测试查询全部方法
     * @Author LinLuoChen
     * @Date  11:22
     **/
    @Test
    public void  QueryDSLTest(){
        User user = new User();
        List<User> list = userService.findAll(user);
        System.out.println(list);
    }

}
复制代码

测试结果,可以运行 ~~

虽然说 QueryDSL 也可以做增删改查,但是个人不建议使用(仅限单表),因为单表操作,其实使用 Jpa 就可以了,包括 Jpa 的动态查询,都是很适合单表的,不管是代码量还是效率个人感觉都比 QueryDSL 要快,尤其是代码量,少了不止一点半点,但是连表操作的话,就比较偏向于 QueryDSL 了,特别好用!!下边是连表操作的 QueryDSL ,另外说一下上边只是演示一下 QueryDSL 的使用方法,单表还是建议用 Jpa 比较快!

---------------------------------------------------- 手动分界线 ----------------------------------------------------

package com.cs.querydsl.service.impl;

import com.cs.querydsl.dao.LocDao;
import com.cs.querydsl.model.Loc;
import com.cs.querydsl.model.QLoc;
import com.cs.querydsl.model.QUser;
import com.cs.querydsl.service.LocService;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.QueryResults;
import com.querydsl.core.Tuple;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.thymeleaf.util.StringUtils;

import javax.annotation.PostConstruct;
import javax.persistence.EntityManager;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @ClassName:LocServiceImpl
 * @Description:TODO 接口实现类
 * @Author LinLuoChen
 * @Date 2019/7/10/14:09
 * @Version V1.0
 **/
@Service
public class LocServiceImpl implements LocService {

    @Autowired
    LocDao locDao;

    @Autowired
    private EntityManager entityManager;

    //查询工厂实体
    private JPAQueryFactory queryFactory;

    //实例化控制器完成后执行该方法实例化JPAQueryFactory
    @PostConstruct
    public void initFactory()
    {
        queryFactory = new JPAQueryFactory(entityManager);
    }

    /**
     * @Description 查询全部
     * @Author LinLuoChen
     * @Date  10:53
     * @return java.util.List<com.cs.querydsl.model.Loc>
     **/
    @Override
    public List<Loc> findAll(Loc loc) {
        // 使用 QueryDSL 进行查询
        QLoc qLoc = QLoc.loc1;
        QUser qUser = QUser.user;
        // 定于获取条件
        BooleanBuilder booleanBuilder = new BooleanBuilder();
        // 要查询的条件
        if(!StringUtils.isEmpty(loc.getLoc())){
            // 放入要查询的条件信息
            booleanBuilder.and(qLoc.loc.contains(loc.getLoc()));
        }
        //连接查询条件(Loc.id = User.id )
        booleanBuilder.and(qLoc.id.eq(qUser.id));
        // 使用 QueryDSL 进行多表联合查询
        QueryResults<Tuple> listResult = queryFactory
                .select(QLoc.loc1,QUser.user)
                .from(qLoc, qUser)//查询两表
                .where(booleanBuilder)
                .fetchResults();
        //遍历 java8 自带流转换成集合
        List<Loc> collect = listResult.getResults().stream().map(tuple -> {
            Loc lcs = tuple.get(qLoc);
            return lcs;
        }).collect(Collectors.toList());
        return collect;
    }
}
复制代码

查看结果

源码示例地址:spring-boot-querydsl.zip

猜你喜欢

转载自juejin.im/post/7095617242385088542