概述
select后置风格
和原生SQL不同,在Jimmer提供的DSL中,select
语句出现在where
,orderBy
,groupBy
,having
之后,例如
- Java
- Kotlin
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(); ❸
val books = sqlClient
.createQuery(Book::class) { ❶
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
,orderBy
,groupBy
,having
,都是直接修改当前查询对象 -
❷处调用
select
,把可变查询对象转化为不可变查询对象。以该对象为目标的操作持续到❸处为止所谓不可变查询对象,指对其进行任何操作,比如,
distinct
,limit
,forUpdate
,reselect
,withoutSortingAndPaging
,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
是最原始的查询,query1
、query2
、query3
都是基于它创建的其他查询。limit
方法并不会改变原本的query
本身,而是创建新的不可变查询对象。最终,
query1
、query2
、query3
共享的相同的筛选条件、排序和结构投影,只是分页范围不同而已。它们可并存,彼此并不影响。另外,
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指定)