Mybatis包分页查询java公共类
mybatis底层的分页sql语句因为须要我们自己去手动写。而实现分页显示的时候我们须要依据分页查询条件查询符合条件的总记录数和记录的具体情况。因此,若是不去实现封装一下的话,我们须要写两条SQL语句去实现它。一次用于查询记录数目。一次用于查询分页显示的具体记录。
当项目中碰到非常多须要分页的时候,我们便对于每个Mapper.xml文件都须要去写两条SQL语句。
极其麻烦。代码重用----必须重用。所以,一个公共方法的分页需求应运而生。
直接上分页公共代码,事实上现的原理是使用了拦截器的拦截作用。拦截一类分页查询的请求。我们依据传进来的參数是否是须要interceptor()方法中拦截的參数,是的话则拦截,并运行对应的SQL追加,否则,不进行追加。直接放行。视作普通查询。
须要在Mybatis的配置文件里配置载入server的时候载入该公共类:mybatis-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties></properties>
<plugins>
<plugin interceptor="com.iboxpay.clear.filter.PaginationInterceptor"></plugin>
</plugins>
</configuration>
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
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.factory.DefaultObjectFactory;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 分页拦截器
* @since 10.20.2014
*/
@Intercepts({@Signature(type=StatementHandler.class,method="prepare",args={Connection.class})})
public class PaginationInterceptor implements Interceptor {
private final Logger logger = LoggerFactory.getLogger(PaginationInterceptor.class);
private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
MetaObject metaStatementHandler = MetaObject.forObject(statementHandler,
DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY);
// 分离代理对象链(因为目标类可能被多个拦截器拦截,从而形成多次代理。通过以下的两次循环
// 能够分离出最原始的的目标类)
while (metaStatementHandler.hasGetter("h")) {
Object object = metaStatementHandler.getValue("h");
metaStatementHandler = MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY,
DEFAULT_OBJECT_WRAPPER_FACTORY);
}
// 分离最后一个代理对象的目标类
while (metaStatementHandler.hasGetter("target")) {
Object object = metaStatementHandler.getValue("target");
metaStatementHandler = MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY,
DEFAULT_OBJECT_WRAPPER_FACTORY);
}
MappedStatement mappedStatement = (MappedStatement)
metaStatementHandler.getValue("delegate.mappedStatement");
// 仅仅重写须要分页的sql语句。通过MappedStatement的ID匹配。默认重写以Page结尾的
// MappedStatement的sql
BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql");
Object parameterObject = boundSql.getParameterObject();
if(parameterObject instanceof PageParam){
if (parameterObject == null) {
throw new NullPointerException("parameterObject is null!");
} else {
PageParam page = (PageParam)parameterObject;
String sql = boundSql.getSql();
// 重写sql
String pageSql = buildPageSql(sql, page);
metaStatementHandler.setValue("delegate.boundSql.sql", pageSql);
metaStatementHandler.setValue("delegate.rowBounds.offset",
RowBounds.NO_ROW_OFFSET);
metaStatementHandler.setValue("delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT);
Connection connection = (Connection) invocation.getArgs()[0];
// 重设分页參数里的总页数等
setPageParameter(sql, connection, mappedStatement, boundSql, page);
}
}
// 将运行权交给下一个拦截器
return invocation.proceed();
}
private String buildPageSql(String sql, PageParam page) {
if (page != null) {
StringBuilder pageSql = new StringBuilder();
pageSql = buildPageSqlForOracle(sql, page);
return pageSql.toString();
} else {
return sql;
}
}
public StringBuilder buildPageSqlForOracle(String sql, PageParam page) {
StringBuilder pageSql = new StringBuilder(100);
String beginrow = String.valueOf((page.getCurrentPage() - 1) * page.getPageSize());
String endrow = String.valueOf(page.getCurrentPage() * page.getPageSize());
pageSql.append("select * from ( select temp.*, rownum row_id from ( ");
pageSql.append(sql);
pageSql.append(" ) temp where rownum <= ").append(endrow);
pageSql.append(") where row_id > ").append(beginrow);
return pageSql;
}
/**
* 从数据库里查询总的记录数并计算总页数,回写进分页參数<code>PageParam</code>,这样调用
* 者就可用通过 分页參数<code>PageParam</code>获得相关信息。
*
* @param sql
* @param connection
* @param mappedStatement
* @param boundSql
* @param page
* @throws SQLException
*/
private void setPageParameter(String sql, Connection connection, MappedStatement mappedStatement,
BoundSql boundSql, PageParam page) throws SQLException {
// 记录总记录数
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.setTotalCount(totalCount);
int totalPage = totalCount / page.getPageSize() + ((totalCount % page.getPageSize() == 0) ? 0 : 1);
page.setTotalPage(totalPage);
} catch (SQLException e) {
logger.error("exception", e);
} finally {
try {
rs.close();
} catch (SQLException e) {
logger.error("exception", e);
}
try {
countStmt.close();
} catch (SQLException e) {
logger.error("exception", e);
}
}
}
private void setParameters(PreparedStatement ps, MappedStatement mappedStatement, BoundSql boundSql,
Object parameterObject) throws SQLException {
ParameterHandler parameterHandler = new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);
parameterHandler.setParameters(ps);
}
@Override
public Object plugin(Object target) {
if (target instanceof StatementHandler) {
return Plugin.wrap(target, this);
} else {
return target;
}
}
@Override
public void setProperties(Properties arg0) {
}
}
将日志的过滤模式调到DEBUG模式,控制台能够打印出SQL
使用上述方法处理的分页查询,其仅仅须要一条SQL语句就能够(Mapper.xml文件的SQL)
<select id="selectChannelSettleByParam" parameterType="PageParam" resultMap="RS_CHANNELSETTLE">
<![CDATA[
select *
]]>
from channlsettle where 1=1
<if test="params.channelSettleModel.channelId != null and 1000 != params.channelSettleModel.channelId">AND CHANNL_ID=#{params.channelSettleModel.channelId}</if>
<if test="params.channelSettleModel.clearStartTime != null and '' != params.channelSettleModel.clearStartTime">
<![CDATA[
AND to_number(CLEAR_DATE) >= to_number(substr(#{params.channelSettleModel.clearStartTime},0,8))
]]>
</if>
<if test="params.channelSettleModel.clearEndTime != null and '' != params.channelSettleModel.clearEndTime">
<![CDATA[
AND to_number(CLEAR_DATE) <= to_number(substr(#{params.channelSettleModel.clearEndTime},0,8))
]]>
</if>
order by INSTDATE desc
</select>
控制台打印的SQL:
第一条:select count(0) from (select * from channlsettle where 1=1 AND CHANNL_ID=? AND to_number(CLEAR_DATE) >= to_number(substr(?
,0,8)) AND to_number(CLEAR_DATE) <= to_number(substr(?
,0,8)) order by INSTDATE desc)
第二条:select * from ( select temp.*, rownum row_id from ( select * from channlsettle where 1=1 AND CHANNL_ID=? AND to_number(CLEAR_DATE) >= to_number(substr(?
,0,8)) AND to_number(CLEAR_DATE) <= to_number(substr(?
,0,8)) order
by INSTDATE desc ) temp where rownum <= 20) where row_id > 0
从而让公共类实现了我们须要在Mapper.xml配置文件里反复写入两条SQL的工作,以后没一个分页查询都能够使用。
版权声明:本文博客原创文章,博客,未经同意,不得转载。
Mybatis包分页查询java公共类的更多相关文章
- springmvc+mybatis 实现分页查询
为简化分页功能,设计了一个分页的JSP标签,只需要在页面使用分页标签,就可以完成所有页面的分页功能. 1. 项目结构和数据库设计 (1) 项目结构: (2) 数据库设计 2. PageModel.ja ...
- SpringBoot整合Mybatis关于分页查询的方法
最近公司在用到SpringBoot整合Mybatis时当web端页面数据增多时需要使用分页查询以方便来展示数据.本人对分页查询进行了一些步骤的总结,希望能够帮助到有需要的博友.如有更好的方式,也希望评 ...
- spring-boot 集合mybatis 的分页查询
spring-boot 集合mybatis 的github分页查询 一.依赖包 <!-- mysql 数据库驱动. --> <dependency> <groupId&g ...
- mybatis之分页查询
1)StudentDao.java /** * 持久层*/ public class StudentDao { /** * 增加学生 */ public void add(Student studen ...
- 亿级别记录的mongodb分页查询java代码实现
1.准备环境 1.1 mongodb下载 1.2 mongodb启动 C:\mongodb\bin\mongod --dbpath D:\mongodb\data 1.3 可视化mongo工具Robo ...
- 使用mybatis实现分页查询示例代码分析
*******************************************分页查询开始*************************************************** ...
- Mybatis 使用分页查询亿级数据 性能问题 DB使用ORACLE
一般用到了mybatis框架分页就不用自己写了 直接用RowBounds对象就可以实现,但这个性能确实很低 今天我用到10w级得数据分页查询,到后面几页就迭代了很慢 用于记录 1.10万级数据如下 [ ...
- mybatis中分页查询
1 如果在查询方法中有多个参数,可以使用map对象将所有数据都存储进去.比如分页查询,需要用到两个参数,可以将这两个参数包装到map中. 例子:分页查询 dao层方法 public List<S ...
- Mybatis的分页查询
示例1:查询业务员的联系记录 1.控制器代码(RelationController.java) //分页列出联系记录 @RequestMapping(value="toPage/custom ...
随机推荐
- 如何成为游戏的生产者——第二章:如何开始你的编程(开发环境的搭建、C++语言适应)
如何成为游戏的生产者--文章二章:怎样開始你的编程 小故事:上节说到我六年级打开了那本C语言的书,然后其实我还是没看懂.好像看懂了一些printf语句.之后遇到了史无前例的困难--怎么让代码执行起来. ...
- apache本地多域配置(wampserver本地多域配置)
当我们在当地发展.通常在浏览器中输入 http://localhost/项目目录名 测试Web文件,你有没有想过在本地浏览器中,输入自己设定的名字进入项目目录,名相关的问题. 比方我想配置一个主域名w ...
- android JNI 简单demo(2)它JNI demo 写
android JNI 简单demo(2)它JNI demo 写 一.搭建Cygwin 环境:http://blog.csdn.net/androidolblog/article/details/25 ...
- IDEA14中安装go语言插件
在IntelliJ IDEA14中安装go语言插件 go语言的集成开发环境仍不成熟,试用了liteide,感觉很不适应,弹出菜单对程序员的干扰太大.所以就试大牌的IntelliJ IDEA,这工具本来 ...
- CSS不常见问题汇总
写css有一段时间了,其间也遇到一些问题,跟大家分享一下 IE10+滚动条自动以藏问题,导致滚动部分页面看起来不正常 html, body {-ms-overflow-style: scrollbar ...
- ViewGroup可实现上下、各地跑马灯效果滚动
先上效果图: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdGFuZ25lbmd3dQ==/font/5a6L5L2T/fontsize/400/fill ...
- Scan IP relocate/failover其它段后不能ping通过
或手动集群重启单个节点srvctl relocate scan_listener后.群集网络段ping IP,VIP.SCAN IP正常.其他段ping SCAN IP 不通.其原因是,该路由ARP表 ...
- 24L01/SI24R1调试笔记
1.SPI MSB优先,8Bit寄存器地址与内容: 2.寄存器结构与之前使用的LT8900不同,分为R.W寄存器与特殊功能寄存器: 3.特别注意:在TX.RX.RT中断或者轮询后置1,必须写1清零与清 ...
- jsRender模板引擎
jsRender模板引擎 上一篇最后提到了模板,并尝试自己编写一个最简单版本:有些朋友可能用过 jqtmpl,这是一个基于jquery的模板引擎,不过它已经不再更新了,而且据说渲染速度比较慢.这里介绍 ...
- UVA - 11324 The Largest Clique 强连通缩点+记忆化dp
题目要求一个最大的弱联通图. 首先对于原图进行强连通缩点,得到新图,这个新图呈链状,类似树结构. 对新图进行记忆化dp,求一条权值最长的链,每一个点的权值就是当前强连通分量点的个数. /* Tarja ...