# QueryDSL

1,QueryDSL仅仅是一个通用的查询框架,专注于通过Java API构建类型安全的SQL查询。

2,Querydsl可以通过一组通用的查询API为用户构建出适合不同类型ORM框架或者是SQL的查询语句,也就是说QueryDSL是基于各种ORM框架以及SQL之上的一个通用的查询框架。

3,借助QueryDSL可以在任何支持的ORM框架或者SQL平台上以一种通用的API方式来构建查询。目前QueryDSL支持的平台包括JPA,JDO,SQL,Java Collections,RDF,Lucene,Hibernate Search。

# Querydsl for JPA

使用类型安全的方式书写原生JPQL

Querydsl for JPAJPQL(类SQL语法,类型不安全) 和 Criteria(复杂度偏高,学习曲线较陡峭) 查询的替代方案

# Querydsl for SQL

使用类型安全的方式书写原生SQL

  1. 和JPA方式的比较(Native表示原生SQL)

    • Native不需要JPA对象,JPA需要。
    • Native需要直连数据库生成Q对象(可自定义前缀,一般定义为N),JPA需要读取JPA对象生成Q对象(不可自定义前缀)
    • Native的灵活性比JPA高,可以出色解决JPA中对子查询嵌套等的短板,通常原生SQL能实现的,Native也能实现
    • JPA的易操作性比Native要好,可全面使用JPA对象的各种特性
    • Native方式的执行过程:java对象 > 解析成sql语句 > 提交给数据库
    • JPA方式的执行过程:java对象 > 解析成JPQL语句(如果用的是Hibernate,则解析成HQL语句) > 解析成sql语句 > 提交给数据库
    • JPA 和 Native均支持不同数据库方言,并可自动转换语法,可以在数据库中无缝切换(如果在使用Native时,自定义了template表达式,并使用了数据库特性的函数方法时,可能导致不同数据库之间无法平滑切换

    综上:优先使用JPA方式,当JPA无法满足生产需求时,才考虑使用Native方式

  2. 集成方式

I. 导入依赖包和插件

<!-- Querydsl for SQL的依赖包 -->
<dependency>
  <groupId>com.querydsl</groupId>
  <artifactId>querydsl-sql</artifactId>
  <version>${querydsl.version}</version>
</dependency>

<dependency>
  <groupId>com.querydsl</groupId>
  <artifactId>querydsl-sql-codegen</artifactId>
  <version>${querydsl.version}</version>
  <scope>provided</scope>
</dependency>


<!-- Querydsl for SQL的插件 -->
<plugin>
  <groupId>com.querydsl</groupId>
  <artifactId>querydsl-maven-plugin</artifactId>
  <version>${querydsl.version}</version>
  <executions>
      <execution>
          <goals>
              <goal>export</goal>
          </goals>
      </execution>
  </executions>
  <configuration>
      <namePrefix>N</namePrefix>
      <sourceFolder></sourceFolder>
      <!-- 只需要写需要生成的表名,按英文逗号分隔,表名支持LIKE语法方式进行命名 -->
      <tableNamePattern>electrode_%,sys_file</tableNamePattern>
      <!-- 数据库连接信息,改成你自己的 -->
      <jdbcDriver>com.mysql.cj.jdbc.Driver</jdbcDriver>
      <jdbcUrl>jdbc:mysql://192.168.1.55:3306/kg_industry_gxjgzx</jdbcUrl>
      <jdbcUser>kg_industry_gxjgzx</jdbcUser>
      <jdbcPassword>kg_industry_gxjgzx</jdbcPassword>
      <!-- 不建议改 -->
      <packageName>com.jfbrother.nativesql.domain</packageName>
      <targetFolder>target/generated-sources/java</targetFolder>
  </configuration>
  <dependencies>
      <!-- 上方使用哪种数据库,这里就需要添加对应的依赖 -->
      <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>8.0.22</version>
      </dependency>
  </dependencies>
</plugin>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

II. 在启动类构造 SQLQueryFactoryBean

@Bean
  public SQLQueryFactory sqlQueryFactory(@Qualifier("primaryDataSource") DataSource dataSource){
      SQLTemplates templates = new MySQLTemplates();
      return new SQLQueryFactory(new com.querydsl.sql.Configuration(templates), dataSource);
  }
1
2
3
4
5

III. 在service中注入 SQLQueryFactory

@Autowired
private SQLQueryFactory sqlQueryFactory;
1
2

Ⅳ. 含有子查询的例子,无子查询写法和JPA类似,但是建议直接使用JPA模式,不要采用该原生SQL模式

NElectrodeProceSpecs nElectrodeProceSpecs = NElectrodeProceSpecs.electrodeProceSpecs;
NElectrodeProceSplit nElectrodeProceSplit = NElectrodeProceSplit.electrodeProceSplit;

SubQueryExpression subQuery1 = SQLExpressions.select(Expressions.stringPath("id")).from(nElectrodeProceSpecs).groupBy(nElectrodeProceSpecs.id).where(nElectrodeProceSpecs.createTime.gt(1));
SubQueryExpression subQuery2 = SQLExpressions.select(nElectrodeProceSplit.id, nElectrodeProceSplit.electrodeProceSpecsId).from(nElectrodeProceSplit);

List<Tuple> fetch = sqlQueryFactory.select(Expressions.template(String.class, "ss.electrode_proce_specs_id"),
        Expressions.template(String.class, "ss.id"))
        .from(subQuery1, Expressions.stringPath("dd"))
        .leftJoin(subQuery2, Expressions.stringPath("ss"))
        .on(Expressions.template(String.class, "dd.id").eq(
                Expressions.template(String.class, "ss.electrode_proce_specs_id")
        ))
        .limit(10)
        .fetch();
if (fetch.size() > 0) {
    log.debug(fetch.get(0).get(Expressions.template(String.class, "ss.electrode_proce_specs_id")));
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18