HasorDB 分页与方言
分页查询
HasorDB 内置了分页查询机制,使用方便且无需任何配置。具体工作方式为:
- 框架会先生成一条未经改写的最终执行 SQL 及参数,并通过
BoundSql
类型承载。 - 然后会根据
PageSqlDialect
接口将原始 SQL 处理成分页 SQL。结果仍然是 BoundSql
类型承载。 - 执行最终的 SQL 完成分页查询
LambdaTemplate 方式
使用 LambdaTemplate
进行分页查询
// 构造 LambdaTemplate 和初始化一些数据
DataSource dataSource = DsUtils.dsMySql();
LambdaTemplate lambdaTemplate = new LambdaTemplate(dataSource);
lambdaTemplate.loadSQL("CreateDB.sql");
// 构建分页对象,每页 3 条数据(默认第一页的页码为 0)
Page pageInfo = new PageObject();
pageInfo.setPageSize(3);
// 分页查询数据
List<TestUser> pageData1 = lambdaTemplate.lambdaQuery(TestUser.class)
.usePage(pageInfo)
.queryForList();
// 分页查询下一页数据
pageInfo.nextPage();
List<TestUser> pageData2 = lambdaTemplate.lambdaQuery(TestUser.class)
.usePage(pageInfo)
.queryForList();
DalSession 方式
以一个简单对查询为例:
<select id="queryListByAge">
select * from `test_user` where age = #{age}
</select>
Mapper 无需任何修改,若使用 DalSession
方式执行 分页 Mapper 则需要构建分页对象然后传递给 queryStatement
方法。
Map<String, Object> ages = new HashMap<>();
ages.put("age", 26);
PageObject page = new PageObject();
page.setPageSize(20);
List<Object> result = dalSession.queryStatement("queryListByAge", ages, page);
Mapper 接口方式
首先将 Mapper queryListByAge
方法映射到接口上,然后在接口方法中增加 Page 参数对象。例如:
@RefMapper("...")
public interface PageExecuteDal {
List<TestUser> queryListByAge(@Param("age") int age, Page pageInfo);
}
或者如下。区别于上面的是可以选择返回一个分页结果对象 PageResult
,分页结果对象中包含了分页信息和总数数据。
提示
使用分页结果对象会产生额外的一条 count
查询。
@RefMapper("...")
public interface PageExecuteDal {
PageResult<TestUser> queryListByAge(@Param("name") String name, Page pageInfo);
}
分页对象
HasorDB 提供了一个分页工具类 PageObject
, 它实现了 Page
接口。并提供了如下一些工具属性/方法。
名称 | 描述 |
---|---|
属性 pageSize
|
页大小,默认是 -1 表示无穷大 |
属性 currentPage
|
当前页号 |
属性 pageNumberOffset
|
页码偏移量(例如:从1页作为起始页,可以设置为 1。否则第一页的页码是 0) |
方法 int getFirstRecordPosition()
|
获取本页第一个记录的索引位置 |
方法 int getTotalPage()
|
获取总页数 |
方法 int getTotalCount()
|
获取记录总数 |
方法 void firstPage()
|
移动到第一页 |
方法 void previousPage()
|
移动到上一页 |
方法 void nextPage()
|
移动到下一页 |
方法 void lastPage()
|
移动到最后一页 |
方法 Map<String, Object> toPageInfo()
|
获取分页信息 |
toPageInfo
方法会返回如下一个 Map。
{
"enable" : true, // 是否启用分页
"pageSize" : 20, // 页大小
"totalCount" : 200, // 总记录数
"totalPage" : 10, // 页总数
"currentPage" : 0, // 当前页码
"recordPosition" : 0// 第一条记录的起始记录位置
}
方言
和方言相关的接口一共有 4 个,其中 SqlDialect
是所有其它接口都继承的公共接口。
-
SqlDialect
基础接口,负责管理关键词清单、生成表名、列名 -
ConditionSqlDialect
负责条件相关的生成,例如:like 语句 -
InsertSqlDialect
负责高级 insert
语句生成,例如处理:冲突策略 -
PageSqlDialect
负责分页语句生成。
提示
实现自定义方言最佳的路线是继承 AbstractDialect
抽象类,它已经实现了 SqlDialect
,ConditionSqlDialect
两个接口。
内置方言实现
HasorDB 默认会根据 JDBC 的链接字符串自动匹配方言,支持如下数据库:
数据库 | 编码 | 方言类名 | JDBC串识别前缀 |
---|---|---|---|
DB2 | db2
|
Db2Dialect
|
jdbc:db2:***
|
Apache Derby | derby
|
DerbyDialect
|
jdbc:derby:*** 、jdbc:log4jdbc:derby:***
|
达梦 | dm
|
DmDialect
|
jdbc:dm:***
|
H2 | H2
|
H2Dialect
|
jdbc:h2::*** 、jdbc:log4jdbc:h2:***
|
Hive | hive
|
HiveDialect
|
jdbc:hive:*** 、jdbc:hive2:***
|
HSQL | hsql
|
HSQLDialect
|
jdbc:hsqldb:*** 、jdbc:log4jdbc:hsqldb:***
|
Apache Impala | impala
|
ImpalaDialect
|
jdbc:impala:***
|
IBM Informix | informix
|
InformixDialect
|
jdbc:informix-sqli:*** 、jdbc:log4jdbc:informix-sqli:***
|
人大金仓 | kingbase
|
KingbaseDialect
|
jdbc:kingbase:***
|
MariaDB | mariadb
|
MariaDBDialect
|
jdbc:mariadb:***
|
MYSQL | mysql
|
MySqlDialect
|
jdbc:mysql:*** 、jdbc:cobar:*** 、jdbc:log4jdbc:mysql:***
|
Oracle | oracle12c
|
Oracle12cDialect
|
-- |
Oracle | oracle
|
OracleDialect
|
jdbc:oracle:*** 、jdbc:log4jdbc:oracle:***
|
Phoenix | phoenix
|
PhoenixDialect
|
jdbc:phoenix:***
|
PostgreSQL | postgresql
|
PostgreSqlDialect
|
jdbc:postgresql:*** 、jdbc:log4jdbc:postgresql:***
|
SQLite | sqlite
|
SqlLiteDialect
|
jdbc:sqlite:***
|
SQL Server | sqlserver
|
SqlServer2005Dialect
|
jdbc:microsoft:*** 、jdbc:log4jdbc:microsoft:*** 、jdbc:sqlserver:*** 、jdbc:log4jdbc:sqlserver:***
|
虚谷数据库 | xugu
|
XuGuDialect
|
jdbc:xugu:***
|
自定义方言
若想实现 分页方言 自定义只需要继承 AbstractDialect
抽象类,然后额外在实现 PageSqlDialect
接口即可。
PageSqlDialect
接口有两个方法,分别用于生成改写后的分页查询 SQL、以及计算 count 的 SQL。
public interface PageSqlDialect extends SqlDialect {
public default BoundSql countSql(BoundSql boundSql) {
return new BoundSql.BoundSqlObj("SELECT COUNT(*) FROM (" + boundSql.getSqlString() + ") as TEMP_T", boundSql.getArgs());
}
public BoundSql pageSql(BoundSql boundSql, int start, int limit);
}
提示
若计算总数的 SQL 只是简单的将其放入子查询并且 count 一下,那么只实现 pageSql
用于改写分页语句的 SQL 即可。
使用自己的新方言
对于 LambdaTemplate
类通过下面方式来设置自己的方言实现类
LambdaTemplate lambdaTemplate = ...
lambdaTemplate.setDialect(new MyDialect());
对于 DalSession
需要通过构造方法穿传入。
DalRegistry dalRegistry = ...
DataSource dataSource = ...
DalSession dalSession = new DalSession(dataSource, dalRegistry, new MyDialect());
通过注册方式,然后 HasorDB 自动使用新方言。
以 MySQL 为例,MySQL 的链接字符串格式为 jdbc:mysql:***
- 首先 HasorDB 会通过
connection.getMetaData().getURL()
方式拿到链接字符串 - 然后根据上面 内置方言 表格中的信息匹配到对应的
方言编码
- 最后通过
SqlDialectRegister.findOrCreate(<方言编码>);
方法获取到对应的方言对象。
因此只需要按照上面规则将新的方言注册到 SqlDialectRegister
上即可。如下:
SqlDialectRegister.registerDialectAlias(JdbcUtils.MYSQL, MyDialect.class);
更多建议: