SpringData-JPA QueryDSL 快速入门

SpringData-JPA QueryDSL 快速入门

不可否认的是 JPA 使用是非常方便的,极简化的配置,只需要使用注解,无需任何 xml 的配置文件,语义简单易懂,但是,以上的一切都建立在单表查询的前提下的,我们可以使用 JPA 默认提供的方法,简单加轻松的完成 CRUD 操作。

但是如果涉及到多表动态查询, JPA 的功能就显得有些捉襟见肘了,虽然我们可以使用注解 @Query ,在这个注解中写 SQL 或者 HQL 都是在拼接字符串,并且拼接后的字符串可读性非常的差,当然 JPA 还为我们提供了 Specification 来做这件事情,从我个人使用体验上来讲,可读性虽然还不错,但是在初学者上手的时候, PredicateCriteriaBuilder 使用方式估计能劝退不少人,而且如果直接执行 SQL 连表查询,获得是一个 Object[] ,类型是什么?字段名是什么?这些都无法直观的获得,还需我们手动将 Object[] 映射到我们需要的 Model 类里面去,这种使用体验无疑是极其糟糕的。

这一切都在 QueryDSL 出世以后终结了, QueryDSL 语法与 SQL 非常相似,代码可读性非常强,异常简介优美,,并且与 JPA 高度集成,无需多余的配置,从笔者个人使用体验上来讲是非常棒的。可以这么说,只要会写 SQL ,基本上只需要看一下示例代码完全可以达到入门的级别。

QueryDSL 简介:

QueryDSL 是一个非常活跃的开源项目,目前在 Github 上的发布的 Release 版本已经多达 251 个版本,目前最新版是 4.2.1 ,并且由 Querydsl Google组 和 StackOverflow 两个团队提供支持。

QueryDSL 是一个框架,可用于构造静态类型的类似SQL的查询。可以通过诸如 QueryDSL 之类的 API 构造查询,而不是将查询编写为内联字符串或将其外部化为XML文件。

1 环境配置

引入maven依赖和插件

SpringBoot 内部已规定了版本


<dependency>
    <groupId>com.querydslgroupId>
    <artifactId>querydsl-aptartifactId>
    <scope>providedscope>
dependency>


<dependency>
    <groupId>com.querydslgroupId>
    <artifactId>querydsl-jpaartifactId>
dependency>


<plugin>
    <groupId>com.mysema.mavengroupId>
    <artifactId>apt-maven-pluginartifactId>
    <version>1.1.3version>
    <executions>
        <execution>
            <goals>
                <goal>processgoal>
            goals>
            <configuration>
                <outputDirectory>target/generated-sources/javaoutputDirectory>
                <processor>com.querydsl.apt.jpa.JPAAnnotationProcessorprocessor>
            configuration>
        execution>
    executions>
plugin>

2 通过mvn插件生成Query类

运行 mvn compile, 将生成Query实体(target包内),以Q+实体类名为名称。

3 使用

1 创建BaseService,后其他service都继承BaseService 通过 JPAQueryFactory进行增删改查操作

public class BaseService {
    @Autowired
    protected EntityManager entityManager;
    protected JPAQueryFactory jpaQueryFactory;

    @PostConstruct
    public void init(){
        jpaQueryFactory = new JPAQueryFactory(entityManager);
    }
}

删除

@Test
public void QDSL1(){
 	QMtProductInfo mtProductInfo = QMtProductInfo.mtProductInfo;
    //delete from mt_product_info wher id =1 or name = '删除'
    BooleanExpression eq = mtProductInfo.id.eq(1);
    BooleanExpression eq2 = eq.or( mtProductInfo.name.eq("删除" ));

    jpaQueryFactory.delete(mtProductInfo).where(eq2).execute();
}

修改

@Test
@Transactional
public void QDSL_update(){
    QMtProductInfo mtProductInfo = QMtProductInfo.mtProductInfo;

    //update mt_product_info set name = "删除" where id =2 or name ='张三'
    jpaQueryFactory.update(mtProductInfo)
    .set(mtProductInfo.name,"删除")
    .where(
    mtProductInfo.id.eq(2)
    .and(mtProductInfo.name.eq("张三"))
    );
}

查询

单表查询
@Test
public void QDSL_query1(){
    QMtProductInfo mtProductInfo = QMtProductInfo.mtProductInfo;

    //返回的类型 和 查询的字段
    QBean<MtProductInfo> title = Projections.bean(MtProductInfo.class, mtProductInfo.id, mtProductInfo.summarize.as("name"));

    List<MtProductInfo> fetch = jpaQueryFactory.select(title)
        .from(mtProductInfo) //要查询的表
        .where(mtProductInfo.id.ne(1))//查询条件
        .fetch();//开始查询

    fetch.forEach(System.out::println);

}
多表查询

多表联查返回Map

 @Test
public void QDSL_query2(){

    QMtProductInfo mtProductInfo = QMtProductInfo.mtProductInfo;
    QMtComFile mtComFile = QMtComFile.mtComFile;

    //创建查询内容和查询条件
    List<Tuple> fetch = jpaQueryFactory.select(mtProductInfo.id, mtProductInfo.name, mtComFile.filename)
        .from(mtProductInfo, mtComFile)
        .where(mtProductInfo.indexIcon.eq(mtComFile.id)) //2表联查关系
        .fetch();

    //处理查询结果 封装为map
    List<Map> collect = fetch.stream().map(o -> {
        Map map = new HashMap();
        map.put("id", o.get(mtProductInfo.id));
        map.put("name", o.get(mtProductInfo.name));
        map.put("filename", o.get(mtComFile.filename));
        return map;
    }).collect(Collectors.toList());

    System.out.println(collect);
}

多表联查返回对象

@Test
public void QDSL_query2(){
    QMtProductInfo mtProductInfo = QMtProductInfo.mtProductInfo;
    QMtComFile mtComFile = QMtComFile.mtComFile;

    //将结果映射为 MtProductInfo 通过 字段名映射
    QBean<MtProductInfo> bean = Projections.bean(MtProductInfo.class, mtProductInfo.id, mtProductInfo.name, mtComFile.filename);

    //创建查询内容和查询条件
    List<MtProductInfo> fetch = jpaQueryFactory.select(bean)
    .from(mtProductInfo, mtComFile)
    .where(mtProductInfo.indexIcon.eq(mtComFile.id)) //2表联查关系
    .fetch();

    System.out.println(fetch);
}
排序和分页
 @Test
public void QDSL_query2(){

    QMtProductInfo mtProductInfo = QMtProductInfo.mtProductInfo;
    QMtComFile mtComFile = QMtComFile.mtComFile;

    //将结果映射为 MtProductInfo 通过 字段名映射
    QBean<MtProductInfo> bean = Projections.bean(MtProductInfo.class, mtProductInfo.id, mtProductInfo.name, mtComFile.filename);

    //创建分页
    PageRequest pageRequest = PageRequest.of(10, 5);

    //创建查询内容和查询条件
    List<MtProductInfo> fetch = jpaQueryFactory.select(bean)
        .from(mtProductInfo, mtComFile)
        .where(mtProductInfo.indexIcon.eq(mtComFile.id)) //2表联查关系
        .orderBy(mtProductInfo.name.asc(),mtProductInfo.status.desc()) //排序
        .offset(pageRequest.getOffset()) //获取 offset
        .limit(pageRequest.getPageSize())
        //获取 pageSize
        .fetch();

    fetch.forEach(System.out::println);
}

你可能感兴趣的:(springBoot,spring,jpa)