mybatis :实现mybatis分页
上一篇文章里已经讲到了mybatis与spring MVC的集成,并且做了一个列表展示,显示出所有article 列表,但没有用到分页,在实际的项目中,分页是肯定需要的。而且是物理分页,不是内存分页。对于物理分页方案,不同的数据库,有不同的实现方法,对于mysql 来说 就是利用 limit offset,pagesize 方式来实现的。oracle 是通过rownum 来实现的,如果你熟悉相关数据库的操作,是一样的很好扩展,本文以mysql 为例子来讲述.先看一下效果图(源代码在文章最后提供下载):

实现mybatis 物理分页,一个最简单的方式是,是在你的mapper的SQL语句中直接写类似如下方式 :
<select id="getUserArticles" parameterType="Your_params" resultMap="resultUserArticleList">
select user.id,user.userName,user.userAddress,article.id aid,article.title,article.content from user,article
where user.id=article.userid and user.id=#{id} limit #{offset},#{pagesize}
</select>
请注意这里的 parameterType 是你传入的参数类,或者map ,里面包含了offset,pagesize ,和其他你需要的参数,用这种方式,肯定可以实现分页。这是简单的一种方式。但更通用的一种方式是用 mybatis 插件的方式. 参考了网上的很多资料 ,mybatis plugin 方面的资料。写自己的插件.
package com.yihaomen.util; import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.Properties; import javax.xml.bind.PropertyException; import org.apache.ibatis.builder.xml.dynamic.ForEachSqlNode;
import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.ExecutorException;
import org.apache.ibatis.executor.statement.BaseStatementHandler;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.ParameterMode;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.property.PropertyTokenizer;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.TypeHandlerRegistry; @Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class }) })
public class PagePlugin implements Interceptor { private static String dialect = "";
private static String pageSqlId = ""; @SuppressWarnings("unchecked")
public Object intercept(Invocation ivk) throws Throwable { if (ivk.getTarget() instanceof RoutingStatementHandler) {
RoutingStatementHandler statementHandler = (RoutingStatementHandler) ivk
.getTarget();
BaseStatementHandler delegate = (BaseStatementHandler) ReflectHelper
.getValueByFieldName(statementHandler, "delegate");
MappedStatement mappedStatement = (MappedStatement) ReflectHelper
.getValueByFieldName(delegate, "mappedStatement"); if (mappedStatement.getId().matches(pageSqlId)) {
BoundSql boundSql = delegate.getBoundSql();
Object parameterObject = boundSql.getParameterObject();
if (parameterObject == null) {
throw new NullPointerException("parameterObject error");
} else {
Connection connection = (Connection) ivk.getArgs()[0];
String sql = boundSql.getSql();
String countSql = "select count(0) from (" + sql + ") myCount";
System.out.println("总数sql 语句:"+countSql);
PreparedStatement countStmt = connection
.prepareStatement(countSql);
BoundSql countBS = new BoundSql(
mappedStatement.getConfiguration(), countSql,
boundSql.getParameterMappings(), parameterObject);
setParameters(countStmt, mappedStatement, countBS,
parameterObject);
ResultSet rs = countStmt.executeQuery();
int count = 0;
if (rs.next()) {
count = rs.getInt(1);
}
rs.close();
countStmt.close(); PageInfo page = null;
if (parameterObject instanceof PageInfo) {
page = (PageInfo) parameterObject;
page.setTotalResult(count);
} else if(parameterObject instanceof Map){
Map<String, Object> map = (Map<String, Object>)parameterObject;
page = (PageInfo)map.get("page");
if(page == null)
page = new PageInfo();
page.setTotalResult(count);
}else {
Field pageField = ReflectHelper.getFieldByFieldName(
parameterObject, "page");
if (pageField != null) {
page = (PageInfo) ReflectHelper.getValueByFieldName(
parameterObject, "page");
if (page == null)
page = new PageInfo();
page.setTotalResult(count);
ReflectHelper.setValueByFieldName(parameterObject,
"page", page);
} else {
throw new NoSuchFieldException(parameterObject
.getClass().getName());
}
}
String pageSql = generatePageSql(sql, page);
System.out.println("page sql:"+pageSql);
ReflectHelper.setValueByFieldName(boundSql, "sql", pageSql);
}
}
}
return ivk.proceed();
} private void setParameters(PreparedStatement ps,
MappedStatement mappedStatement, BoundSql boundSql,
Object parameterObject) throws SQLException {
ErrorContext.instance().activity("setting parameters")
.object(mappedStatement.getParameterMap().getId());
List<ParameterMapping> parameterMappings = boundSql
.getParameterMappings();
if (parameterMappings != null) {
Configuration configuration = mappedStatement.getConfiguration();
TypeHandlerRegistry typeHandlerRegistry = configuration
.getTypeHandlerRegistry();
MetaObject metaObject = parameterObject == null ? null
: configuration.newMetaObject(parameterObject);
for (int i = 0; i < parameterMappings.size(); i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
String propertyName = parameterMapping.getProperty();
PropertyTokenizer prop = new PropertyTokenizer(propertyName);
if (parameterObject == null) {
value = null;
} else if (typeHandlerRegistry
.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else if (boundSql.hasAdditionalParameter(propertyName)) {
value = boundSql.getAdditionalParameter(propertyName);
} else if (propertyName
.startsWith(ForEachSqlNode.ITEM_PREFIX)
&& boundSql.hasAdditionalParameter(prop.getName())) {
value = boundSql.getAdditionalParameter(prop.getName());
if (value != null) {
value = configuration.newMetaObject(value)
.getValue(
propertyName.substring(prop
.getName().length()));
}
} else {
value = metaObject == null ? null : metaObject
.getValue(propertyName);
}
TypeHandler typeHandler = parameterMapping.getTypeHandler();
if (typeHandler == null) {
throw new ExecutorException(
"There was no TypeHandler found for parameter "
+ propertyName + " of statement "
+ mappedStatement.getId());
}
typeHandler.setParameter(ps, i + 1, value,
parameterMapping.getJdbcType());
}
}
}
} private String generatePageSql(String sql, PageInfo page) {
if (page != null && (dialect !=null || !dialect.equals(""))) {
StringBuffer pageSql = new StringBuffer();
if ("mysql".equals(dialect)) {
pageSql.append(sql);
pageSql.append(" limit " + page.getCurrentResult() + ","
+ page.getShowCount());
} else if ("oracle".equals(dialect)) {
pageSql.append("select * from (select tmp_tb.*,ROWNUM row_id from (");
pageSql.append(sql);
pageSql.append(") tmp_tb where ROWNUM<=");
pageSql.append(page.getCurrentResult() + page.getShowCount());
pageSql.append(") where row_id>");
pageSql.append(page.getCurrentResult());
}
return pageSql.toString();
} else {
return sql;
}
} public Object plugin(Object arg0) {
// TODO Auto-generated method stub
return Plugin.wrap(arg0, this);
} public void setProperties(Properties p) {
dialect = p.getProperty("dialect");
if (dialect ==null || dialect.equals("")) {
try {
throw new PropertyException("dialect property is not found!");
} catch (PropertyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
pageSqlId = p.getProperty("pageSqlId");
if (dialect ==null || dialect.equals("")) {
try {
throw new PropertyException("pageSqlId property is not found!");
} catch (PropertyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} }
此插件有两个辅助类:PageInfo,ReflectHelper,你可以下载源代码参考。
写了插件之后,当然需要在 mybatis 的配置文件Configuration.xml 里配置这个插件
<plugins>
<plugin interceptor="com.yihaomen.util.PagePlugin">
<property name="dialect" value="mysql" />
<property name="pageSqlId" value=".*ListPage.*" />
</plugin>
</plugins>
请注意,这个插件定义了一个规则,也就是在mapper中sql语句的id 必须包含ListPage才能被拦截。否则将不会分页处理.
插件写好了,现在就可以在 spring mvc 中的controller 层中写一个方法来测试这个分页:
@RequestMapping("/pagelist")
public ModelAndView pageList(HttpServletRequest request,HttpServletResponse response){
int currentPage = request.getParameter("page")==null?1:Integer.parseInt(request.getParameter("page"));
int pageSize = 3;
if (currentPage<=0){
currentPage =1;
}
int currentResult = (currentPage-1) * pageSize;
System.out.println(request.getRequestURI());
System.out.println(request.getQueryString());
PageInfo page = new PageInfo();
page.setShowCount(pageSize);
page.setCurrentResult(currentResult);
List<Article> articles=iUserOperation.selectArticleListPage(page,1);
System.out.println(page);
int totalCount = page.getTotalResult();
int lastPage=0;
if (totalCount % pageSize==0){
lastPage = totalCount % pageSize;
}
else{
lastPage =1+ totalCount / pageSize;
}
if (currentPage>=lastPage){
currentPage =lastPage;
}
String pageStr = "";
pageStr=String.format("<a href=\"%s\">上一页</a> <a href=\"%s\">下一页</a>",
request.getRequestURI()+"?page="+(currentPage-1),request.getRequestURI()+"?page="+(currentPage+1) );
//制定视图,也就是list.jsp
ModelAndView mav=new ModelAndView("list");
mav.addObject("articles",articles);
mav.addObject("pageStr",pageStr);
return mav;
}

一号门原创
mybatis :实现mybatis分页的更多相关文章
- Mybatis Generator实现分页功能
Mybatis Generator实现分页功能 分类: IBATIS2013-07-17 17:03 882人阅读 评论(1) 收藏 举报 mybatisibatisgeneratorpage分页 众 ...
- SpringBoot+Mybatis配置Pagehelper分页插件实现自动分页
SpringBoot+Mybatis配置Pagehelper分页插件实现自动分页 **SpringBoot+Mybatis使用Pagehelper分页插件自动分页,非常好用,不用在自己去计算和组装了. ...
- SpringBoot+Mybatis+PageHelper实现分页
SpringBoot+Mybatis+PageHelper实现分页 mybatis自己没有分页功能,我们可以通过PageHelper工具来实现分页,非常简单方便 第一步:添加依赖 <depend ...
- 【MyBatis】MyBatis之分页
关于MyBatis的搭建可以参见“MyBatis的配置”,MyBatis是对JDBC底层代码的封装,关于Oracle.MySQL.SqlServer的分页可以查看Oracle.SqlServer.My ...
- SpringBoot集成Mybatis并具有分页功能PageHelper
SpringBoot集成Mybatis并具有分页功能PageHelper 环境:IDEA编译工具 第一步:生成测试的数据库表和数据 SET FOREIGN_KEY_CHECKS=0; ...
- Mybatis学习---Mybatis分页插件 - PageHelper
1. Mybatis分页插件 - PageHelper说明 如果你也在用Mybatis,建议尝试该分页插件,这个一定是最方便使用的分页插件. 该插件目前支持Oracle,Mysql,MariaDB,S ...
- 轻量级封装DbUtils&Mybatis之三MyBatis分页
MyBatis假分页 参考DefaultResultSetHandler的skipRows方法. 温馨提示:部分代码请参考轻量级封装DbUtils&Mybatis之一概要 解决方案 1)之前公 ...
- 【MyBatis】MyBatis分页插件PageHelper的使用
好多天没写博客了,因为最近在实习,大部分时间在熟悉实习相关的东西,也没有怎么学习新的东西,这周末学习了MyBatis的一个分页插件PageHelper,虽然没有那么的强大(我在最后会说明它的缺点),但 ...
- Mybatis的PageHelper分页插件的PageInfo的属性参数,成员变量的解释,以及页面模板
作者:个人微信公众号:程序猿的月光宝盒 //当前页 private int pageNum; //每页的数量 private int pageSize; //当前页的数量 private int si ...
- Spring Boot整合tk.mybatis及pageHelper分页插件及mybatis逆向工程
Spring Boot整合druid数据源 1)引入依赖 <dependency> <groupId>com.alibaba</groupId> <artif ...
随机推荐
- oracle和mysql的分页
如果我们是通过JDBC的方式访问数据库,那么就有必要根据数据库类型采取不同的SQL分页语句,对于MySql数据库,我们可以采用limit语句进行分页,对于Oracle数据库,我们可以采用rownum的 ...
- Mysql学习总结(26)——MySQL子查询
mysql中虽然有连接查询实现多表连接查询,但是连接查询的性能很差,因此便出现了子查询. 1.理论上,子查询可以出现在查询语句的任何位置,但实际应用中多出现在from后和where后.出现在from后 ...
- poj3134 Power Calculus IDA*
好端端的一道搜索题目,,,硬生生的被我弄成了乱搞题,,,枚举当前的maxd,深搜结果,然而想到的剪枝方法都没有太好的效果,,,最后用一个贪心乱搞弄出来了,,, 贪心:每次必用上一次做出来的数字与其他数 ...
- ajax异步刷新
前台js <script type="text/javascript"> function getLands() { $.ajax({ url:"httpse ...
- Qt之图形(绘制漂亮的圆弧)
简述 综合前面对二维绘图的介绍,想必我们对一些基本绘图有了深入的了解,下面我们来实现一些漂亮的图形绘制. 简述 圆形 效果 源码 弧形 效果 源码 文本 效果 源码 旋转 效果 源码 圆形 经常地,我 ...
- 实验了一下对于struct引用的成员的改动
今天写代码的时候,不确定struct用引用传递给函数的时候,他的成员在函数里面改变的时候,是否能影响到外面. 实验了一下 #include <stdio.h> #include <s ...
- C++ 数字、string 简便互转
一.数字转为 string 类型 借用 sprintf 函数: char buffer[256]; int counter = 10; sprintf(buffer,"%04i", ...
- IOS音频架构之Audio Unit
在前面的章节部分我们已经对IOS音频结构有了一个清晰的认识,知道Audio Unit是位于整个音频结构的最底层,这一层非常多API已经開始和硬件打交道了.所以比較复杂,有了前面的基础再来看这个部分就比 ...
- php 数组元素高速去重
1.使用array_unique方法进行去重 对数组元素进行去重.我们通常会使用array_unique方法,使用这种方法能够把数组中的元素去重. <?php $arr = array(1,1, ...
- YTUOJ-计算该日在本年中是第几天(用户自己定义类型)
题目描写叙述 定义一个结构体变量(包含年.月.日).编写一个函数days,由主函数将年.月.日传递给函数days,计算出该日在本年中是第几天并将结果传回主函数输出. 输入 年月日 输出 当年第几天 例 ...
