第一个做法,就是直接使用我们的sql语句进行分页,也就是在mapper里面加上分页的语句就好了。

<select id="" parameterType="" resultType="" resultMap="">
Select ROWNUM,ID,NAME FROM(Select ROWNUM as ROWNO, ID,NAME from CHANGED_CONTENT
<where>
<![CDATA[ROWNUM <= #{endRow}]]>
</where>
)
<where>
<![CDATA[ROWNO > #{startRow}]]>
</where>
</select>

然后我们在使用这个dao的时候,传入我们的分页的参数,就可以实现我们的分页需求了。其实很简单。


第二个做法,是一个更为通用的做法,那就是利用mybatis的拦截器,拦截每一个sql,在需要分页的sql加上分页的语句,就可以实现我们的分页功能。

我们可以查看 org.mybatis.spring.SqlSessionFactoryBean,其实他有一个plugin属性,我们可以配置实现一个插件来实现我们的需求。

首先说明一下实现的流程

例如我们有一条sql

String sql =select * from tableXXX where a=xxxx

我们的 拦截器拦截这条sql,然后判断是否是需要分页的,然后将这条sql转化为分页的sql

<span style="font-family: 微软雅黑; background-color: rgb(255, 255, 255);">    String countSql = "select count(1) from (" + sql    + ") tmp_count"  </span>
这样我们就可以得到分页的总页数了。

然后, 拼上我们传入的分页数据,哪一页,每一页几条数据:

select * from ( select row_.*, rownum rownum_ from (   sql        ) row_ ) where rownum_ <=  endString   and rownum_ >  offsetPlaceholder

这样我们就可以得到我们本页的返回了。

具体的代码如下:

首先是实现了ibatis intercepter的pageplugin
public class PagePlugin implements Interceptor {

    private static Logger log = Logger.getLogger("page plugin");
private static Dialect dialectObject = null; // 数据库方言
private static String pageSqlId = ""; // mybaits的数据库xml映射文件中需要拦截的ID(正则匹配) public Object intercept(Invocation ivk) throws Throwable {
if (ivk.getTarget() instanceof RoutingStatementHandler) {
log.info("com.dragon.dao.pulgin.mybatis.plugin.PagePlugin.intercept() enter*****************");
RoutingStatementHandler statementHandler = (RoutingStatementHandler) ivk
.getTarget();
BaseStatementHandler delegate = (BaseStatementHandler) ReflectHelper
.getValueByFieldName(statementHandler, "delegate");
MappedStatement mappedStatement = (MappedStatement) ReflectHelper
.getValueByFieldName(delegate, "mappedStatement");
/**
* 方法1:通过ID来区分是否需要分页..*query.* 方法2:传入的参数是否有page参数,如果有,则分页,
*/
if (mappedStatement.getId().matches(pageSqlId)) { // 拦截需要分页的SQL
BoundSql boundSql = delegate.getBoundSql();
Object parameterObject = boundSql.getParameterObject();// 分页SQL<select>中parameterType属性对应的实体参数,即Mapper接口中执行分页方法的参数,该参数不得为空
if (parameterObject == null) {
//throw new NullPointerException("boundSql.getParameterObject() is null!");
return ivk.proceed();
} else { PageView pageView = null;
if (parameterObject instanceof PageView) { // 参数就是Pages实体
pageView = (PageView) parameterObject;
} else if (parameterObject instanceof Map) {
for (Entry entry : (Set<Entry>) ((Map) parameterObject).entrySet()) {
if (entry.getValue() instanceof PageView) {
pageView = (PageView) entry.getValue();
break;
}
}
} else { // 参数为某个实体,该实体拥有Pages属性
pageView = ReflectHelper.getValueByFieldType(
parameterObject, PageView.class);
if (pageView == null) {
return ivk.proceed();
}
} String sql = boundSql.getSql();
PreparedStatement countStmt = null;
ResultSet rs = null;
try {
Connection connection = (Connection) ivk.getArgs()[0];
String countSql = "select count(1) from (" + sql
+ ") tmp_count"; // 记录统计
countStmt = connection.prepareStatement(countSql);
ReflectHelper.setValueByFieldName(boundSql, "sql",
countSql);
DefaultParameterHandler parameterHandler = new DefaultParameterHandler(
mappedStatement, parameterObject, boundSql);
parameterHandler.setParameters(countStmt);
rs = countStmt.executeQuery();
Long count = 0L;
if (rs.next()) {
count = ((Number) rs.getObject(1)).longValue();
}
pageView.setRowCount(count);
} finally {
try {
rs.close();
} catch (Exception e) {
}
try {
countStmt.close();
} catch (Exception e) {
}
}
String pageSql = generatePagesSql(sql, pageView);
ReflectHelper.setValueByFieldName(boundSql, "sql", pageSql); // 将分页sql语句反射回BoundSql.
}
}
}
return ivk.proceed();
} /**
* 根据数据库方言,生成特定的分页sql
*
* @param sql
* @param page
* @return
*/
private String generatePagesSql(String sql, PageView page) {
if (page != null && dialectObject != null) {
//pageNow默认是从1,而已数据库是从0开始计算的.所以(page.getPageNow()-1)
int pageNow = page.getPageNow();
return dialectObject.getLimitString(sql, (pageNow <= 0 ? 0 : pageNow - 1)
* page.getPageSize(), page.getPageSize());
}
return sql;
} public Object plugin(Object target) {
return Plugin.wrap(target, this);
} public void setProperties(Properties p) {
String dialect = ""; // 数据库方言
dialect = p.getProperty("dialect");
if (StringUtils.isBlank(dialect)) {
try {
throw new PropertyException("dialect property is not found!");
} catch (PropertyException e) {
log.error(e);
}
} else {
try {
dialectObject = (Dialect) Class.forName(dialect)
.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new RuntimeException(dialect + ", init fail!\n" + e);
}
}
pageSqlId = p.getProperty("pageSqlId");//根据id来区分是否需要分页
if (StringUtils.isBlank(pageSqlId)) {
try {
throw new PropertyException("pageSqlId property is not found!");
} catch (PropertyException e) {
log.error(e);
}
}
}
}

然后是实现了dialect的oracledialect 数据库方言让我们区分不同的数据库不同的sql语句

public class OracleDialect extends Dialect {

    public boolean supportsLimit() {
return true;
} public boolean supportsLimitOffset() {
return true;
} public String getLimitString(String sql, int offset, String offsetPlaceholder, int limit, String limitPlaceholder) {
sql = sql.trim();
boolean isForUpdate = false;
if (sql.toLowerCase().endsWith(" for update")) {
sql = sql.substring(0, sql.length() - 11);
isForUpdate = true;
} StringBuffer pagingSelect = new StringBuffer(sql.length() + 100);
if (offset > 0) {
pagingSelect.append("select * from ( select row_.*, rownum rownum_ from ( ");
} else {
pagingSelect.append("select * from ( ");
}
pagingSelect.append(sql);
if (offset > 0) {
// int end = offset+limit;
String endString = offsetPlaceholder + "+" + limitPlaceholder;
pagingSelect.append(" ) row_ ) where rownum_ <= " + endString + " and rownum_ > " + offsetPlaceholder);
} else {
pagingSelect.append(" ) where rownum <= " + limitPlaceholder);
} if (isForUpdate) {
pagingSelect.append(" for update");
} return pagingSelect.toString();
} }

配置mybatis.xml

我们需要在sqlSessionFactory中注册我们的插件,发挥效果
 <bean id="pagePlugin" class="com.xxxxx.pulgin.mybatis.plugin.PagePlugin">
<property name="properties">
<props>
<prop key="dialect">com.dragon.dao.pulgin.jdbc.dialet.OracleDialect</prop>
<prop key="pageSqlId">.*query.*</prop>
</props>
</property>
</bean>

 <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:spring/mybatis.xml" />
<property name="plugins">
<array>
<ref bean="pagePlugin" /> </array>
</property>
<property name="mapperLocations">
<list>
<!-- 自动匹配Mapper映射文件 -->
<value>classpath:com/xxxxx/mapper/*-mapper.xml</value>
</list>
</property>
</bean>

至此,我们的分页效果就做出来了。

charles at P.P 2016-7-14

如何做系列(1)- mybatis 如何实现分页?的更多相关文章

  1. Mybatis Generator实现分页功能

    Mybatis Generator实现分页功能 分类: IBATIS2013-07-17 17:03 882人阅读 评论(1) 收藏 举报 mybatisibatisgeneratorpage分页 众 ...

  2. Mybatis第三方PageHelper分页插件原理

    ​ 欢迎关注公号:BiggerBoy,看更多文章 原文链接:https://mp.weixin.qq.com/s?__biz=MzUxNTQyOTIxNA==&mid=2247485158&a ...

  3. Mybatis中的分页

    Mybatis中有哪些分页方式? 数组分页:查询出全部数据,然后再list中截取需要的部分.(逻辑分页) 优点:效率高     缺点:占用内存比较高 sql分页:只从数据库中查询当前页的数据.(物理分 ...

  4. SpringBoot+Mybatis配置Pagehelper分页插件实现自动分页

    SpringBoot+Mybatis配置Pagehelper分页插件实现自动分页 **SpringBoot+Mybatis使用Pagehelper分页插件自动分页,非常好用,不用在自己去计算和组装了. ...

  5. SpringBoot+Mybatis+PageHelper实现分页

    SpringBoot+Mybatis+PageHelper实现分页 mybatis自己没有分页功能,我们可以通过PageHelper工具来实现分页,非常简单方便 第一步:添加依赖 <depend ...

  6. SpringBoot集成Mybatis并具有分页功能PageHelper

    SpringBoot集成Mybatis并具有分页功能PageHelper   环境:IDEA编译工具   第一步:生成测试的数据库表和数据   SET FOREIGN_KEY_CHECKS=0;   ...

  7. SpringBoot系列-整合Mybatis(注解方式)

    目录 一.常用注解说明 二.实战 三.测试 四.注意事项 上一篇文章<SpringBoot系列-整合Mybatis(XML配置方式)>介绍了XML配置方式整合的过程,本文介绍下Spring ...

  8. Mybatis的PageHelper分页插件的PageInfo的属性参数,成员变量的解释,以及页面模板

    作者:个人微信公众号:程序猿的月光宝盒 //当前页 private int pageNum; //每页的数量 private int pageSize; //当前页的数量 private int si ...

  9. 小白的springboot之路(十五)、mybatis的PageHelper分页插件使用

    0.前言 用mybatis,那么分页必不可少,基本都是用PageHelper这个分页插件,好用方便: 1.实现 1.1.添加依赖: <!-- 3.集成 mybatis pagehelper--& ...

随机推荐

  1. 【JZOJ6273】欠钱

    description analysis 读懂题就可知\(b\)的收益即为\(a\)到\(b\)这一条链上边权的最小值 那么就是动态维护一个森林,询问链上最小值,同时必须满足儿子走向父亲 明显\(LC ...

  2. 用shell脚本执行php删除缓存文件

    <?php #定义删除路径//服务器缓存目录的路径 $path = '/www/wwwroot/****/data/runtime'; #调用删除方法 deleteDir($path); fun ...

  3. 阿里云 Aliplayer高级功能介绍(二):缩略图

    基本介绍 Aliplayer提供了缩略图的功能,让用户在拖动进度条之前知道视频的内容,用户能够得到很好的播放体验,缩略图是显示在Controlbar的上面,并且包含当前的时间,阿里云的媒体处理服务提供 ...

  4. expect离线安装

    expect5.45.4.tar.gz和tcl8.4.11-src.tar.gz压缩包请前往以下链接下载: https://download.csdn.net/download/gangzi221/1 ...

  5. js 常见功能总会

    一.随着页面滚动,元素到达可视区域,显示特殊样式 <!DOCTYPE html> <html lang="en"> <head> <met ...

  6. (转)获取android手机内部存储空间和外部存储空间的参数 && 如何决定一个apk的安装位置

    转:http://blog.csdn.net/zhandoushi1982/article/details/8560233 获取android文件系统的信息,需要Environment类和StatFs ...

  7. VS2010-MFC(对话框:属性页对话框及相关类的介绍)

    转自:http://www.jizhuomi.com/software/164.html 一 属性页对话框的分类 属性页对话框想必大家并不陌生,XP系统中桌面右键点属性,弹出的就是属性页对话框,它通过 ...

  8. day 64 Django基础十之Form和ModelForm组件

    Django基础十之Form和ModelForm组件   本节目录 一 Form介绍 二 Form常用字段和插件 三 From所有内置字段 四 字段校验 五 Hook钩子方法 六 进阶补充 七 Mod ...

  9. SpringAOP中的aop:config标签

    我们使用Spring的AOP功能的时候发现,我们使用普通的配置方式的时候,我们无法精确的确定将切面类中的哪个方法切入到哪个切入点上, 所以我们可以使用aop的专用标签来完成相关的配置.其中主要表现是使 ...

  10. 初探JVM总结

    什么是JVM Java Virtual Machine(Java虚拟机)的缩写 .本质上是一个程序. java语言运行的平台,是ava跨平台的根本. java默认的三种类加载器 BootStrap C ...