跳到主要内容

概述

select后置风格

和原生SQL不同,在Jimmer提供的DSL中,select语句出现在whereorderBygroupByhaving之后,例如

BookTable table = Tables.BOOK_TABLE;

List<Book> books = sqlClient
.createQuery(table)
.where(table.name().eq("SQL in Action"))
.orderBy(table.name().asc(), table.edition().desc())
.select(table)
.limit(10, 100)
.execute();
提示

select放在后面并非Jimmer的首创,首次把这种风格带入主流编程领域的是C#3.5推出的LINQ

这种风格对构建基于强类型DSL框架有天生的优势,因此Jimmer很自然地沿用了这种风格。

代码结构

现在,解释上述代码。

  • ❶处创建查询,得到一个可变查询对象。以该对象为目标的操作持续到❷处为止

    所谓可变查询对象,指对其进行任何操作,比如,where, orderBygroupBy, having,都是直接修改当前查询对象

  • ❷处调用select,把可变查询对象转化为不可变查询对象。以该对象为目标的操作持续到❸处为止

    所谓不可变查询对象,指对其进行任何操作,比如,distinct, limit, forUpdate, reselectwithoutSortingAndPaging, union, unionAll, minus, intersect,都是不会改变当前查询对象,而是创建新的对象

    例如 (为了简短,这段伪码使用kotlin)

    val query = sqlClient.createQuery(Book::class) {
    where(...)
    orderBy(...)
    select(...)
    }
    val query1 = query.limit(10, 0);
    val query2 = query.limit(10, 1);
    val query3 = query.limit(10, 2);

    这里query是最原始的查询,query1query2query3都是基于它创建的其他查询。limit方法并不会改变原本的query本身,而是创建新的不可变查询对象。

    最终,query1query2query3共享的相同的筛选条件、排序和结构投影,只是分页范围不同而已。它们可并存,彼此并不影响。

    另外,select之前的的可变查询没有返回类型,而select之后的不可变查询有返回类型。即,select为查询语句赋予了最终返回类型。

  • ❸处调用execute,执行查询并返回最终数据。

    在这一步之前,无论如何操作和调整DSL,都不会执行SQL操作。

    execute外,还有其他方法可以执行查询

    • fetchOne:假设查询必然返回一条数据,得到这条数据。如果实际执行后发现返回了0或多条数据,则抛出异常

    • fetchOneOrNull:假设查询必然返回0或1条数据,得到这条数据或null。如果实际执行后发现返回了多条数据,则抛出异常

    • fetchOptional:功能同fetchOneOrNull类似,只是把返回类型从null | T变成了java.util.Optional<T>

      警告

      此API仅存在于Java API中,不存在于kotlin API。因为kotlin不需要java.util.Optional<T>

    • map:直接执行,并在返回的原始集合的基础上再进行一次JVM层面的集合map操作。

    • forEach:如果因返回数据太多而不想返回一个大集合,就可以调用forEach并传递一个callback,遍历所有数据

      这就是人们常说的游标查询

    • count:在用户编写的原始数据查询基础上,自动生成分页查询所需要的count聚合查询,并执行获取分页前的数据总行数。

      信息

      这是一个足够智能和高级的操作,请参见分页查询

    提示

    上述所有用于执行查询的方法,都有两个重载版本

    • 无参版本 (上述代码所示),利用Jimmer的连接管理机制 (通常对接spring事务管理机制) 获取JDBC连接并执行。

    • 有参数版本:参数接受一个JDBC连接。特殊情况下,开发人员可以弃Jimmer连接管理机制 (通常对接spring事务管理机制) 于不顾,在自己指定的JDBC连接上执行。

现在,可以用如下简图总结

+-----------------+
| ❶ createQuery |
+-------+---------+
|
可变查询
(以where, orderBy为代表的操作,
直接修改当前查询)
|
|
\|/
+-----------------+
| ❷ select |
+-------+---------+
|
不可变查询
(以limit, distinct为代表的操作,
并不修改当前查询,而是创建新的查询)
|
|
\|/
+-----------------+
| ❸ execute或其他 |
+-------+---------+
|
执行结果
(其类型由❷处select指定)