- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章详解Mybatis极其(最)简(好)单(用)的一个分页插件由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
注意:这篇博客已经和当前的分页插件完全不一样了,所以建议大家通过上面项目地址查看最新的源码和文档来了解.
以前为Mybatis分页查询发愁过,而且在网上搜过很多相关的文章,最后一个都没采用。在分页的地方完全都是手写分页SQL和count的sql,总之很麻烦.
后来有一段时间想从Mybatis内部写一个分页的实现,我对LanguageDriver写过一个实现,自动分页是没问题了,但是查询总数(count)仍然没法一次性解决,最后不了了之.
最近又要用到分页,为了方便必须地写个通用的分页类,因此又再次参考网上大多数的Mybatis分页代码.
实际上在很早之前,有人在github上开源过一个实现,支持MySQL,Oracle,sqlserver的,和上面这个参考的比较类似,考虑的更全面。但是我觉得太多类太麻烦了,所以自己实现了一个只有一个拦截器的类,实际上可以分为两个类,其中一个类被我写成静态类放在了拦截器中,你也可以将Page类提取出来,方便使用Page.
先说实现方法,该插件只有一个类:PageHelper.Java 。
拦截器签名为:
1
2
|
@Intercepts
({
@Signature
(type = StatementHandler.
class
, method =
"prepare"
, args = {Connection.
class
}),
@Signature
(type = ResultSetHandler.
class
, method =
"handleResultSets"
, args = {Statement.
class
})})
|
这里的签名对整个实现和思想至关重要,首先我拦截prepare方法来改分页SQL,来做count查询。然后我拦截handleResultSets方法来获取最后的处理结果,将结果放到Page对象中.
下面是修改分页的代码,是针对Oracle数据进行的修改,如果有用其他数据库的,自己修改这里的代码就可以.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
/**
* 修改原SQL为分页SQL
* @param sql
* @param page
* @return
*/
private
String buildPageSql(String sql, Page page) {
StringBuilder pageSql =
new
StringBuilder(
200
);
pageSql.append(
"select * from ( select temp.*, rownum row_id from ( "
);
pageSql.append(sql);
pageSql.append(
" ) temp where rownum <= "
).append(page.getEndRow());
pageSql.append(
") where row_id > "
).append(page.getStartRow());
return
pageSql.toString();
}
|
之后在下面的setPageParameter方法中一个selelct count语句,这里也需要根据数据库类型进行修改:
1
2
|
// 记录总记录数
String countSql =
"select count(0) from ("
+ sql +
")"
;
|
为什么我不提供对各种数据库的支持呢,我觉得没必要,还有些数据库不支持分页,而且这个插件越简单对使用的开发人员来说越容易理解,越容易修改。修改成自己需要的分页查询肯定不是问题.
最后上完整代码(继续看下去,下面还有使用方法):(点击下载) 。
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
|
package
com.mybatis.util;
import
org.apache.ibatis.executor.parameter.ParameterHandler;
import
org.apache.ibatis.executor.resultset.ResultSetHandler;
import
org.apache.ibatis.executor.statement.StatementHandler;
import
org.apache.ibatis.mapping.BoundSql;
import
org.apache.ibatis.mapping.MappedStatement;
import
org.apache.ibatis.plugin.*;
import
org.apache.ibatis.reflection.MetaObject;
import
org.apache.ibatis.reflection.SystemMetaObject;
import
org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
import
org.apache.log4j.Logger;
import
java.sql.*;
import
java.util.List;
import
java.util.Properties;
/**
* Mybatis - 通用分页拦截器
* @author liuzh/abel533/isea
* Created by liuzh on 14-4-15.
*/
@Intercepts
({
@Signature
(type = StatementHandler.
class
, method =
"prepare"
, args = {Connection.
class
}),
@Signature
(type = ResultSetHandler.
class
, method =
"handleResultSets"
, args = {Statement.
class
})})
public
class
PageHelper
implements
Interceptor {
private
static
final
Logger logger = Logger.getLogger(PageHelper.
class
);
public
static
final
ThreadLocal<Page> localPage =
new
ThreadLocal<Page>();
/**
* 开始分页
* @param pageNum
* @param pageSize
*/
public
static
void
startPage(
int
pageNum,
int
pageSize) {
localPage.set(
new
Page(pageNum, pageSize));
}
/**
* 结束分页并返回结果,该方法必须被调用,否则localPage会一直保存下去,直到下一次startPage
* @return
*/
public
static
Page endPage() {
Page page = localPage.get();
localPage.remove();
return
page;
}
@Override
public
Object intercept(Invocation invocation)
throws
Throwable {
if
(localPage.get() ==
null
) {
return
invocation.proceed();
}
if
(invocation.getTarget()
instanceof
StatementHandler) {
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler);
// 分离代理对象链(由于目标类可能被多个拦截器拦截,从而形成多次代理,通过下面的两次循环
// 可以分离出最原始的的目标类)
while
(metaStatementHandler.hasGetter(
"h"
)) {
Object object = metaStatementHandler.getValue(
"h"
);
metaStatementHandler = SystemMetaObject.forObject(object);
}
// 分离最后一个代理对象的目标类
while
(metaStatementHandler.hasGetter(
"target"
)) {
Object object = metaStatementHandler.getValue(
"target"
);
metaStatementHandler = SystemMetaObject.forObject(object);
}
MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue(
"delegate.mappedStatement"
);
//分页信息if (localPage.get() != null) {
Page page = localPage.get();
BoundSql boundSql = (BoundSql) metaStatementHandler.getValue(
"delegate.boundSql"
);
// 分页参数作为参数对象parameterObject的一个属性
String sql = boundSql.getSql();
// 重写sql
String pageSql = buildPageSql(sql, page);
//重写分页sql
metaStatementHandler.setValue(
"delegate.boundSql.sql"
, pageSql);
Connection connection = (Connection) invocation.getArgs()[
0
];
// 重设分页参数里的总页数等
setPageParameter(sql, connection, mappedStatement, boundSql, page);
// 将执行权交给下一个拦截器
return
invocation.proceed();
}
else
if
(invocation.getTarget()
instanceof
ResultSetHandler) {
Object result = invocation.proceed();
Page page = localPage.get();
page.setResult((List) result);
return
result;
}
return
null
;
}
/**
* 只拦截这两种类型的
* StatementHandler
* ResultSetHandler
* @param target
* @return
*/
@Override
public
Object plugin(Object target) {
if
(target
instanceof
StatementHandler || target
instanceof
ResultSetHandler) {
return
Plugin.wrap(target,
this
);
}
else
{
return
target;
}
}
@Override
public
void
setProperties(Properties properties) {
}
/**
* 修改原SQL为分页SQL
* @param sql
* @param page
* @return
*/
private
String buildPageSql(String sql, Page page) {
StringBuilder pageSql =
new
StringBuilder(
200
);
pageSql.append(
"select * from ( select temp.*, rownum row_id from ( "
);
pageSql.append(sql);
pageSql.append(
" ) temp where rownum <= "
).append(page.getEndRow());
pageSql.append(
") where row_id > "
).append(page.getStartRow());
return
pageSql.toString();
}
/**
* 获取总记录数
* @param sql
* @param connection
* @param mappedStatement
* @param boundSql
* @param page
*/
private
void
setPageParameter(String sql, Connection connection, MappedStatement mappedStatement,
BoundSql boundSql, Page page) {
// 记录总记录数
String countSql =
"select count(0) from ("
+ sql +
")"
;
PreparedStatement countStmt =
null
;
ResultSet rs =
null
;
try
{
countStmt = connection.prepareStatement(countSql);
BoundSql countBS =
new
BoundSql(mappedStatement.getConfiguration(), countSql,
boundSql.getParameterMappings(), boundSql.getParameterObject());
setParameters(countStmt, mappedStatement, countBS, boundSql.getParameterObject());
rs = countStmt.executeQuery();
int
totalCount =
0
;
if
(rs.next()) {
totalCount = rs.getInt(
1
);
}
page.setTotal(totalCount);
int
totalPage = totalCount / page.getPageSize() + ((totalCount % page.getPageSize() ==
0
) ?
0
:
1
);
page.setPages(totalPage);
}
catch
(SQLException e) {
logger.error(
"Ignore this exception"
, e);
}
finally
{
try
{
rs.close();
}
catch
(SQLException e) {
logger.error(
"Ignore this exception"
, e);
}
try
{
countStmt.close();
}
catch
(SQLException e) {
logger.error(
"Ignore this exception"
, e);
}
}
}
/**
* 代入参数值
* @param ps
* @param mappedStatement
* @param boundSql
* @param parameterObject
* @throws SQLException
*/
private
void
setParameters(PreparedStatement ps, MappedStatement mappedStatement, BoundSql boundSql,
Object parameterObject)
throws
SQLException {
ParameterHandler parameterHandler =
new
DefaultParameterHandler(mappedStatement, parameterObject, boundSql);
parameterHandler.setParameters(ps);
}
/**
* Description: 分页
* Author: liuzh
* Update: liuzh(2014-04-16 10:56)
*/
public
static
class
Page<E> {
private
int
pageNum;
private
int
pageSize;
private
int
startRow;
private
int
endRow;
private
long
total;
private
int
pages;
private
List<E> result;
public
Page(
int
pageNum,
int
pageSize) {
this
.pageNum = pageNum;
this
.pageSize = pageSize;
this
.startRow = pageNum >
0
? (pageNum -
1
) * pageSize :
0
;
this
.endRow = pageNum * pageSize;
}
public
List<E> getResult() {
return
result;
}
public
void
setResult(List<E> result) {
this
.result = result;
}
public
int
getPages() {
return
pages;
}
public
void
setPages(
int
pages) {
this
.pages = pages;
}
public
int
getEndRow() {
return
endRow;
}
public
void
setEndRow(
int
endRow) {
this
.endRow = endRow;
}
public
int
getPageNum() {
return
pageNum;
}
public
void
setPageNum(
int
pageNum) {
this
.pageNum = pageNum;
}
public
int
getPageSize() {
return
pageSize;
}
public
void
setPageSize(
int
pageSize) {
this
.pageSize = pageSize;
}
public
int
getStartRow() {
return
startRow;
}
public
void
setStartRow(
int
startRow) {
this
.startRow = startRow;
}
public
long
getTotal() {
return
total;
}
public
void
setTotal(
long
total) {
this
.total = total;
}
@Override
public
String toString() {
return
"Page{"
+
"pageNum="
+ pageNum +
", pageSize="
+ pageSize +
", startRow="
+ startRow +
", endRow="
+ endRow +
", total="
+ total +
", pages="
+ pages +
'}'
;
}
}
}
|
使用该拦截器首先需要在Mybatis配置中配置该拦截器:
1
2
3
|
<
plugins
>
<
plugin
interceptor
=
"com.mybatis.util.PageHelper"
></
plugin
>
</
plugins
>
|
配置拦截器的时候需要注意plugins的位置,plugins位置顺序如下:
1
|
properties?, settings?, typeAliases?, typeHandlers?, objectFactory?, objectWrapperFactory?, plugins?, environments?, databaseIdProvider?, mappers?
|
最后是调用该方法的例子代码(Service层):
1
2
3
4
5
6
7
8
9
10
11
12
|
@Override
public
PageHelper.Page<SysLoginLog> findSysLoginLog(String loginIp,
String username,
String loginDate,
String exitDate,
String logerr,
int
pageNumber,
int
pageSize)
throws
BusinessException {
PageHelper.startPage(pageNumber,pageSize);
sysLoginLogMapper.findSysLoginLog(loginIp, username, loginDate, exitDate, logerr);
return
PageHelper.endPage();
}
|
从上面可以看到使用该插件使用起来是很简单的,只需要在查询前后使用PageHelper的startPage和endPage方法即可,中间代码的调用结果已经存在于Page的result中,如果你在一个返回一个结果的地方调用PageHelper,返回的结果仍然是一个List,取第一个值即可(我想没人会在这种地方这么用,当然这样也不出错).
另外在startPage和endPage中间的所有mybatis代码都会被分页,而且PageHelper只会保留最后一次的结果,因而使用时需要保证每次只在其中执行一个mybatis查询,如果有多个分页,请多次使用startPage和endPage.
由于这里只提供了Oracle的实现,所以我希望参考该分页插件实现的其他数据库的读者也能将相应的代码开源.
项目地址:Mybatis_PageHelper.zip 。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我.
原文链接:http://blog.csdn.net/isea533/article/details/23831273 。
最后此篇关于详解Mybatis极其(最)简(好)单(用)的一个分页插件的文章就讲到这里了,如果你想了解更多关于详解Mybatis极其(最)简(好)单(用)的一个分页插件的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我在互联网上搜索了很多小时,但没有找到满意的结果,所以 -VSTO Addin 和 COM Addin(我们作为类库项目制作并使用 Excel 对象)之间有什么区别?VSTO 项目是否有任何限制,例如
我在互联网上搜索了很多小时,但没有找到满意的结果,所以 -VSTO Addin 和 COM Addin(我们作为类库项目制作并使用 Excel 对象)之间有什么区别?VSTO 项目是否有任何限制,例如
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,
我正在寻找有关如何构建可扩展 WCF 服务器(具有动态加载的服务)的建议,最好使用 System.Addins 或 MEF。 服务器应托管实现最小“插件”API(StartService/StopSe
有没有一种方法可以使用加载浏览器扩展/插件/插件的 headless 浏览器(即 PhantomJS、Selenium)来运行自动测试? 更具体地说,我想模拟广告拦截器(如 Ghostery、ad-b
我是 gradle 的新手,我使用 artifactory 作为我的 repo 服务器。我在网上查看了如何将我的项目发布到我的 repo 服务器,发现我可以使用 maven-publish 或使用 a
我想禁用某些状态的点击/事件,并仅使少数状态可点击。我通读了http://newsignature.github.io/us-map/处的文档,并且找不到与此问题相关的任何内容。 最佳答案 http:
据我了解,在Intellij中使用idea插件打开Maven构建的项目并不是最好的方法,即调用: mvn idea:idea 但是直接打开pom文件(Intellij有默认的Maven插件);同样的事
使用Artifactory plugin对于 Jenkins pipeline 来说是一种幸福,只要遵循文档就可以了。但后来我介绍了Maven Flatten plugin解析父模块和子模块 mvn
我已经安装了Elasticsearch版本1.7.1。一切正常。我也安装了 JDBC 驱动程序。检查下面我的插件文件夹 目录E:\Xampp\htdocs\my-elastic\elasticsear
在我使用 webpack common chunks 插件创建包含第三方库(如 angular、react、lodash 等)的 vendor 包之前,但后来我知道了 webpack dll
我们正在尝试使用(Jenkins、sonar、eclipse ...)安装 CI 平台。 为了让每个开发人员都可以在提交之前对他的代码进行分析,我想知道两种选择: 使用 Sonar 插件运行本地分析。
我知道这是一个比较特殊的问题。尽管如此,也许有些人知道这一点: 我想在 Eclipse 中使用 Maven 编译 Hector=> 分支:0.7.0 和标签:hector-0.7.0-29(https
我卡住了。我一直在尝试寻找或自己创建一个简单的准系统示例,说明如何为 VS 2010 Express 创建 Outlook 插件。我知道这在 VS 2010 Pro 中更简单,但是,在快速版本中真的不
我有以下排除过滤器来忽略所有 R 文件类: findbugs-exclude-filter.xml 当我将它用于 FindBugs-IDEA 插件时,它可以
我刚开始玩 CakePHP,我发现了 Wildflower CMS .我喜欢这个想法,并打算开始修补它。不过,我有一个问题。 在自述文件中,我发现了以下内容:“Wildflower 不是也不会是 Ca
虽然现在大部分情况都是使用n-api来编写插件,但是底层毕竟是v8(和libuv),使用v8编写简单的插件,同时熟悉v8的使用。 本文介绍在写c++插件时,简单又常用的写法,其实本质上,写插件
本篇是 Python 系列教程第 3 篇,更多内容敬请访问我的 Python 合集 Visual Studio Code的安装非常简单,就不放这里增加文章篇幅了。 相比PyCharm,V
Maven – 插件 什么是 Maven 插件? Maven 实际上是一个依赖插件执行的框架,每个任务实际上是由插件完成。Maven 插件通常被用来: 创建 jar 文件 创建 war
我正在编写一个插件来添加带有标签 [deposit_page] 的页面;该标记应替换为一些 PHP 代码。 这就是我所拥有的,但它不起作用。有什么我遗漏或做错了什么吗? function deposi
我是一名优秀的程序员,十分优秀!