MyBatis分页插件:使用很灵活,有全部插件源码和配置,同时有测试代码和日志(目前支持Oracle和MySQL)

来源:互联网 发布:植物转录因子数据库 编辑:程序博客网 时间:2024/06/05 02:01

1、概述:
经过努力写了个分页插件,目前支持MySQL和Oracle。它的使用应该是目前为止最简单的,对于PageHelper据原作者描述使用了ThreadLocal等技术,避免多线程的不一致,PageHelper实现较为复杂,其次也有其定义的startPage这样的开关代码,造成代码侵入,而没有屏蔽PageHelper导致代码污染。

我的插件十分简单易用,代码污染性极小,也无需考虑多线程的问题,反正都是一个事务中处理的,其次使用方法支持四种,十分灵活。


2、插件代码,配置和简易的POJO

我们先看看插件的代码:

package com.learn.mybatis.plugin;import java.beans.PropertyDescriptor;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.Iterator;import java.util.Map;import java.util.Properties;import java.util.Set;import javax.transaction.NotSupportedException;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.SystemMetaObject;import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;import org.apache.ibatis.session.Configuration;/** * * @author ykzhen2015 */@Intercepts({    @Signature(type = StatementHandler.class,            method = "prepare",            args = {Connection.class})})public class PagingPlugin implements Interceptor {    /**     * 插件默认参数,可配置     */    private Integer defaultPage; //默认页码    private Integer defaultPageSize;//默认每页条数    private Boolean defaultUseFlag; //默认是否启用插件    private Boolean defaultCheckFlag; //默认是否检测页码参数    private Boolean defaultCleanOrderBy; //默认是否清除最后一个order by 后的语句    private static final String DB_TYPE_MYSQL = "mysql";    private static final String DB_TYPE_ORACLE = "oracle";    /**     * 插件实现方法     */    @Override    public Object intercept(Invocation invocation) throws Throwable {        StatementHandler stmtHandler = (StatementHandler) getUnProxyObject(invocation.getTarget());        MetaObject metaStatementHandler = SystemMetaObject.forObject(stmtHandler);        String sql = (String) metaStatementHandler.getValue("delegate.boundSql.sql");        MappedStatement mappedStatement =  (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement");        String dbType = this.getDataSourceType(mappedStatement);        //不是select语句.        if (!this.checkSelect(sql)) {            return invocation.proceed();        }        BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql");        Object parameterObject = boundSql.getParameterObject();        PageParams pageParams = getPageParamsForParamObj(parameterObject);        if (pageParams == null) { //无法获取分页参数,不进行分页。            return invocation.proceed();        }        //获取配置中是否启用分页功能.        Boolean useFlag = pageParams.getUseFlag() == null? this.defaultUseFlag : pageParams.getUseFlag();        if (!useFlag) {  //不使用分页插件.            return invocation.proceed();        }        //获取相关配置的参数.        Integer pageNum = pageParams.getPage() == null? defaultPage : pageParams.getPage();        Integer pageSize = pageParams.getPageSize() == null? defaultPageSize : pageParams.getPageSize();        Boolean checkFlag = pageParams.getCheckFlag() == null? defaultCheckFlag : pageParams.getCheckFlag();        Boolean cleanOrderBy = pageParams.getCleanOrderBy() == null? defaultCleanOrderBy : pageParams.getCleanOrderBy();        //计算总条数        int total = this.getTotal(invocation, metaStatementHandler, boundSql, cleanOrderBy, dbType);        //回填总条数到分页参数        pageParams.setTotal(total);        //计算总页数.        int totalPage = total % pageSize == 0 ? total / pageSize : total / pageSize + 1;        //回填总页数到分页参数.        pageParams.setTotalPage(totalPage);        //检查当前页码的有效性.        this.checkPage(checkFlag, pageNum, totalPage);        //修改sql        return this.preparedSQL(invocation, metaStatementHandler, boundSql, pageNum, pageSize, dbType);    }    /***     * 分离出分页参数.     * @param parameterObject --执行参数     * @return 分页参数     * @throws Exception     */    public PageParams getPageParamsForParamObj(Object parameterObject) throws Exception {        PageParams pageParams = null;        if (parameterObject == null) {            return null;        }        //处理map参数和@Param注解参数,都是MAP        if (parameterObject instanceof Map) {            @SuppressWarnings("unchecked")            Map<String, Object> paramMap = (Map<String, Object>) parameterObject;            Set<String> keySet = paramMap.keySet();            Iterator<String> iterator = keySet.iterator();            while(iterator.hasNext()) {                String key = iterator.next();                Object value = paramMap.get(key);                if (value instanceof PageParams) {                    return (PageParams)value;                }            }        } else if (parameterObject instanceof PageParams) { //参数POJO继承了PageParams            return (PageParams) parameterObject;        } else { //从POJO尝试读取分页参数.            Field[] fields = parameterObject.getClass().getDeclaredFields();            //尝试从POJO中获得类型为PageParams的属性            for (Field field : fields) {                if (field.getType() == PageParams.class) {                    PropertyDescriptor pd = new PropertyDescriptor (field.getName(), parameterObject.getClass());                    Method method = pd.getReadMethod();                    return (PageParams) method.invoke(parameterObject);                }            }        }        return pageParams;    }    /**     * 判断是否sql语句.     * @param sql     * @return     */    private boolean checkSelect(String sql) {        String trimSql = sql.trim();        int idx = trimSql.toLowerCase().indexOf("select");        return idx == 0;    }    /**     * 检查当前页码的有效性.     * @param checkFlag     * @param pageNum     * @param pageTotal     * @throws Throwable     */    private void checkPage(Boolean checkFlag, Integer pageNum, Integer pageTotal) throws Throwable  {        if (checkFlag) {            //检查页码page是否合法.            if (pageNum > pageTotal) {                throw new Exception("查询失败,查询页码【" + pageNum + "】大于总页数【" + pageTotal + "】!!");            }        }    }    /**     * 预编译改写后的SQL,并设置分页参数     * @param invocation     * @param metaStatementHandler     * @param boundSql     * @param pageNum     * @param pageSize     * @param dbType     * @throws IllegalAccessException     * @throws InvocationTargetException     */    private Object preparedSQL(Invocation invocation, MetaObject metaStatementHandler, BoundSql boundSql, int pageNum, int pageSize, String dbType) throws Exception {        //获取当前需要执行的SQL        String sql = boundSql.getSql();        String newSql = this.getPageDataSQL(sql, dbType);        //修改当前需要执行的SQL        metaStatementHandler.setValue("delegate.boundSql.sql", newSql);        //执行编译,这里相当于StatementHandler执行了prepared()方法,这个时候,就剩下2个分页参数没有设置。        Object statementObj = invocation.proceed();        //设置两个分页参数。        this.preparePageDataParams((PreparedStatement)statementObj, pageNum, pageSize, dbType);        return statementObj;    }    /**     * 获取总条数.     *     * @param ivt Invocation     * @param metaStatementHandler statementHandler     * @param boundSql sql     * @param cleanOrderBy 是否清除order by语句     * * @param dbType     * @return sql查询总数.     * @throws Throwable 异常.     */    private int getTotal(Invocation ivt, MetaObject metaStatementHandler, BoundSql boundSql, Boolean cleanOrderBy, String dbType) throws Throwable {        //获取当前的mappedStatement        MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement");        //配置对象        Configuration cfg = mappedStatement.getConfiguration();        //当前需要执行的SQL        String sql = (String) metaStatementHandler.getValue("delegate.boundSql.sql");        //去掉最后的order by语句        if (cleanOrderBy) {            sql = this.cleanOrderByForSql(sql);        }        String countSql = this.getTotalSQL(sql, dbType);        //获取拦截方法参数,根据插件签名,知道是Connection对象.        Connection connection = (Connection) ivt.getArgs()[0];        PreparedStatement ps = null;        int total = 0;        try {            //预编译统计总数SQL            ps = connection.prepareStatement(countSql);            //构建统计总数SQL            BoundSql countBoundSql = new BoundSql(cfg, countSql, boundSql.getParameterMappings(), boundSql.getParameterObject());            //构建MyBatis的ParameterHandler用来设置总数Sql的参数。            ParameterHandler handler = new DefaultParameterHandler(mappedStatement, boundSql.getParameterObject(), countBoundSql);            //设置总数SQL参数            handler.setParameters(ps);            //执行查询.            ResultSet rs = ps.executeQuery();            while (rs.next()) {                total = rs.getInt("total");            }        } finally {            //这里不能关闭Connection否则后续的SQL就没法继续了。            if (ps != null) {                ps.close();            }        }        return total;    }    private String cleanOrderByForSql(String sql) {        StringBuilder sb = new StringBuilder(sql);        String newSql = sql.toLowerCase();        //如果没有order语句,直接返回        if (newSql.indexOf("order") == -1) {            return sql;        }        int idx = newSql.lastIndexOf("order");        return sb.substring(0, idx).toString();    }    /**     * 从代理对象中分离出真实对象.     *     * @param ivt --Invocation     * @return 非代理StatementHandler对象     */    private Object getUnProxyObject(Object target) {        MetaObject metaStatementHandler = SystemMetaObject.forObject(target);        // 分离代理对象链(由于目标类可能被多个拦截器拦截,从而形成多次代理,通过循环可以分离出最原始的的目标类)        Object object = null;        while (metaStatementHandler.hasGetter("h")) {            object = metaStatementHandler.getValue("h");        }        if (object == null) {            return target;        }        return object;    }    /**     * 生成代理对象     * @param statementHandler 原始对象     * @return 代理对象     */    @Override    public Object plugin(Object statementHandler) {        return Plugin.wrap(statementHandler, this);    }    /**     * 设置插件配置参数。     * @param props     */    @Override    public void setProperties(Properties props) {        String strDefaultPage = props.getProperty("default.page", "1");        String strDefaultPageSize = props.getProperty("default.pageSize", "50");        String strDefaultUseFlag = props.getProperty("default.useFlag", "false");        String strDefaultCheckFlag = props.getProperty("default.checkFlag", "false");        String StringDefaultCleanOrderBy = props.getProperty("default.cleanOrderBy", "false");        this.defaultPage = Integer.parseInt(strDefaultPage);        this.defaultPageSize = Integer.parseInt(strDefaultPageSize);        this.defaultUseFlag = Boolean.parseBoolean(strDefaultUseFlag);        this.defaultCheckFlag = Boolean.parseBoolean(strDefaultCheckFlag);        this.defaultCleanOrderBy = Boolean.parseBoolean(StringDefaultCleanOrderBy);    }    /**     * TODO     * 计算总数的SQL,     * 这里需要根据数据库的类型改写SQL,目前支持MySQL和Oracle     * @param currSql —— 当前执行的SQL     * @return 改写后的SQL     * @throws NotSupportedException     */    private String getTotalSQL(String currSql, String dbType) throws NotSupportedException {        if (DB_TYPE_MYSQL.equals(dbType)) {            return  "select count(*) as total from (" + currSql + ") $_paging";        } else if (DB_TYPE_ORACLE.equals(dbType)) {            return "select count(*) as total from (" + currSql +")";        } else {            throw new NotSupportedException("当前插件未支持此类型数据库");        }    }    /**     * TODO 需要使用其他数据库需要改写     * 分页获取参数的SQL     * 这里需要根据数据库的类型改写SQL,目前支持MySQL和Oracle     * @param currSql —— 当前执行的SQL     * @return 改写后的SQL     * @throws NotSupportedException     */    private String getPageDataSQL(String currSql, String dbType) throws NotSupportedException {        if (DB_TYPE_MYSQL.equals(dbType)) {            return "select * from (" + currSql + ") $_paging_table limit ?, ?";        } else if (DB_TYPE_ORACLE.equals(dbType)) {            return " select * from (select cur_sql_result.*, rownum rn from (" + currSql + ") cur_sql_result  where rownum <= ?) where rn > ?";        } else {            throw new NotSupportedException("当前插件未支持此类型数据库");        }    }    /**     * TODO 需要使用其他数据库需要改写     * 使用PreparedStatement预编译两个分页参数,如果数据库的规则不一样,需要改写设置的参数规则。目前支持MySQL和Oracle     * @throws SQLException     * @throws NotSupportedException     *     */    private void preparePageDataParams(PreparedStatement ps, int pageNum, int pageSize, String dbType) throws Exception {        //prepared()方法编译SQL,由于MyBatis上下文没有我们分页参数的信息,所以这里需要设置这两个参数.            //获取需要设置的参数个数,由于我们的参数是最后的两个,所以很容易得到其位置            int idx = ps.getParameterMetaData().getParameterCount();            if (DB_TYPE_MYSQL.equals(dbType)) {                //最后两个是我们的分页参数.                ps.setInt(idx -1, (pageNum - 1) * pageSize);//开始行                ps.setInt(idx, pageSize); //限制条数            } else if (DB_TYPE_ORACLE.equals(dbType)) {                ps.setInt(idx -1, pageNum * pageSize);//结束行                ps.setInt(idx, (pageNum - 1) * pageSize); //开始行            } else {                throw new NotSupportedException("当前插件未支持此类型数据库");            }    }    /**     *     * TODO 需要使用其他数据库需要改写     * 目前支持MySQL和Oracle     * @param mappedStatement     * @return     * @throws Exception     */    private String getDataSourceType(MappedStatement mappedStatement) throws Exception {        Connection conn = null;        String dbConnectionStr = null;        try {            conn = mappedStatement.getConfiguration().getEnvironment().getDataSource().getConnection();            dbConnectionStr  = conn.toString();        } finally {            if (conn != null) {                conn.close();            }        }        if (null == dbConnectionStr || dbConnectionStr.trim().equals(""))  {            throw new NotSupportedException("当前插件未能获得数据库连接信息。");        }        dbConnectionStr = dbConnectionStr.toLowerCase();        if (dbConnectionStr.contains(DB_TYPE_MYSQL)) {            return DB_TYPE_MYSQL;        } else if (dbConnectionStr.contains(DB_TYPE_ORACLE)) {            return DB_TYPE_ORACLE;        } else {            throw new NotSupportedException("当前插件未支持此类型数据库");        }    }}


如果你是使用非Oracle或者MySQL的,你需要修改注解有TODO的方法,修改是也很简单。

有了这个插件,还要配置一下,MyBatis的配置文件如下:

<configuration>......<plugins><plugin interceptor="com.learn.mybatis.plugin.PagingPlugin">    <!-- 默认页码 --><property name="default.page" value="1" /><!-- 默认每页条数--><property name="default.pageSize" value="20" /><!-- 是否启动分页插件功能  --><property name="default.useFlag" value="true" /><!-- 是否检查页码有效性,如果非有效,则抛出异常. --><property name="default.checkFlag" value="false" /><!-- 针对哪些含有order by的SQL,是否去掉最后一个order by 以后的SQL语句,提高性能 --><property name="default.cleanOrderBy" value="false" /></plugin></plugins>......</configuration>

上面我们可以看到一些默认值,可以根据我自己定义的一个POJO修改上面配置的默认值,这个POJO十分简单,它符合JavaBean的一切规范,如下:(其属性含义见其注解)

package com.learn.mybatis.plugin;import java.util.List;/** * * @author ykzhen2015 */public class PageParams {private Integer page;//第几页private Integer pageSize;//每页限制条数private Boolean useFlag;//是否启动插件,如果不启动,则不作分页private Boolean checkFlag;//是否检测页码的有效性,如果为true,而页码大于最大页数,则抛出异常private Boolean cleanOrderBy;//是否清除最后order by 后面的语句private Integer total; //总条数,插件会回填这个值private Integer totalPage; //总页数,插件会回填这个值.public Integer getPage() {return page;}public void setPage(Integer page) {this.page = page;}public Integer getPageSize() {return pageSize;}public void setPageSize(Integer pageSize) {this.pageSize = pageSize;}public Boolean getUseFlag() {return useFlag;}public void setUseFlag(Boolean useFlag) {this.useFlag = useFlag;}public Boolean getCheckFlag() {return checkFlag;}public void setCheckFlag(Boolean checkFlag) {this.checkFlag = checkFlag;}public Boolean getCleanOrderBy() {return cleanOrderBy;}public void setCleanOrderBy(Boolean cleanOrderBy) {this.cleanOrderBy = cleanOrderBy;}public Integer getTotal() {return total;}public void setTotal(Integer total) {this.total = total;}public Integer getTotalPage() {return totalPage;}public void setTotalPage(Integer totalPage) {this.totalPage = totalPage;}}

当以下属性被设置会有这样的效果(如果都不设置则使用xml配置的默认值):

  • page  --插件默认设置default.page作废,采取这个值,整数型
  • pageSize --插件默认设置default.pageSize作废,采取这个值,整数型
  • useFlag --插件默认设置default.useFlag作废,采取这个值,布尔值
  • checkFlag --插件默认设置default.checkFlag作废,采取这个值,布尔值
  • cleanOrderBy -- 插件默认设置default.cleanOrderBy作废,采用这个值,布尔值

而:

total  ——代表总条数,插件回自动帮我们回填,整数型

totalPage ——代表总页数,插件回自动帮我们回填,整数型


3、插件的使用:

这个插件使用起来十分简单,只要传递给MyBatis的SqlMap以下的方式都是允许的:

  • 继承com.learn.mybatis.plugin.PageParams
  • 使用map,但是map中的键值对应,有一个值是com.learn.mybatis.plugin.PageParams类型
  • 使用@Param注解,只要里面有一个参数是com.learn.mybatis.plugin.PageParams类型
  • 使用POJO,但是这个POJO中有一个属性为com.learn.mybatis.plugin.PageParams类型

以上4种形式都可以使用这个分页插件,是不是很灵活易用??

让我们试用一下这个插件,看看这四种传递参数的方法。


现在我们定义一个map.xml如下:

<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.learn.mybatis.chapter1.mapper.RoleMapper">    <select id="getRole" parameterType="long" resultType="com.learn.mybatis.chapter1.po.TRole">        select id, role_name as roleName, note from t_role where id=#{id}    </select>    <select id="selectAllRole" parameterType="com.learn.mybatis.plugin.TestParams" resultType="com.learn.mybatis.chapter1.po.TRole">        select id, role_name as roleName, note from t_role        <where>        <if test="roleName != null">        role_name like concat('%', #{roleName}, '%')        </if>        </where>        order by id desc    </select>    <select id="selectAllRole2" parameterType="com.learn.mybatis.plugin.TestParams2" resultType="com.learn.mybatis.chapter1.po.TRole">        select id, role_name as roleName, note from t_role        <where>        <if test="roleName != null">        role_name like concat('%', #{roleName}, '%')        </if>        </where>        order by id desc    </select>    <select id="selectRoleByMap" parameterType="map" resultType="com.learn.mybatis.chapter1.po.TRole">        select id, role_name as roleName, note from t_role        <where>        <if test="roleName != null">        role_name like concat('%', #{roleName}, '%')        </if>        </where>        order by id desc    </select>    <select id="selectRoleByMap2" resultType="com.learn.mybatis.chapter1.po.TRole">        select id, role_name as roleName, note from t_role    </select>    <select id="selectRoleByKey"  resultType="com.learn.mybatis.chapter1.po.TRole">        select id, role_name as roleName, note from t_role        <where>        <if test="roleName != null">        role_name like concat('%', #{roleName}, '%')        </if>        </where>        order by id desc    </select>    <select id="test$sql" resultType="com.learn.mybatis.chapter1.po.TRole">        select id, role_name as roleName, note from ${tableName}        <where>        <if test="roleName != null">        role_name like concat('%', #{roleName}, '%')        </if>        </where>        order by role_name desc    </select></mapper>

定义其接口:

package com.learn.mybatis.chapter1.mapper;import java.util.List;import java.util.Map;import org.apache.ibatis.annotations.Param;import org.apache.ibatis.session.RowBounds;import com.learn.mybatis.chapter1.po.TRole;import com.learn.mybatis.plugin.PageParams;import com.learn.mybatis.plugin.TestParams;import com.learn.mybatis.plugin.TestParams2;public interface RoleMapper {//不含分页参数,就不会启用public TRole getRole(Long id);//继承方式public List<TRole> selectAllRole(TestParams pageParams);//参数为POJO,但是POJO内部包含一个类型为com.learn.mybatis.plugin.PageParams的属性public List<TRole> selectAllRole2(TestParams2 testParams2);//使用map,里面有一个com.learn.mybatis.plugin.PageParams类型的值public List<TRole> selectRoleByMap(Map<String, Object> params);//使用注解的形式传递分页参数。public List<TRole> selectRoleByMap2(@Param("roleName") String roleName, @Param("page221232323")  PageParams pageParams);}


好,看到注解,里面已经包含了上述4种传参的方法,这个插件都是支持的。先看到selectAllRole()方法

里面的参数TestParams定义(继承PageParams):

package com.learn.mybatis.plugin;public class TestParams extends PageParams {String roleName;public String getRoleName() {return roleName;}public void setRoleName(String roleName) {this.roleName = roleName;}}
再看到selectAllRole2()方法,里面的参数TestParams2定义(其属性有一个PageParams):

package com.learn.mybatis.plugin;public class TestParams2 {private PageParams pageParams = null;private String roleName;public PageParams getPageParams() {return pageParams;}public void setPageParams(PageParams pageParams) {this.pageParams = pageParams;}public String getRoleName() {return roleName;}public void setRoleName(String roleName) {this.roleName = roleName;}}

好其他的都很简单了。

我们来测试这个接口,测试代码如下,注意看四种方式传递参数,代码的污染是很小的:

package com.learn.mybatis.chapter1.main;import java.util.HashMap;import java.util.Map;import org.apache.ibatis.session.SqlSession;import org.apache.log4j.Logger;import com.learn.mybatis.chapter1.mapper.RoleMapper;import com.learn.mybatis.chapter1.mb.util.MyBatisUtil;import com.learn.mybatis.plugin.PageParams;import com.learn.mybatis.plugin.TestParams;import com.learn.mybatis.plugin.TestParams2;public class MyBatisExample {private static Logger logger = Logger.getLogger(MyBatisExample.class);public static void main(String[] args) {testGetRole();testInherit();testMap();testAtParam();testPojoProperty();}/** * 继承PageParams的参数传递. */public static void testGetRole() {logger.info("#################测试没有分页参数的查询###########################");SqlSession sqlSession = null;try {sqlSession = MyBatisUtil.getSqlSessionFactroy().openSession();RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);roleMapper.getRole(1L);} finally {sqlSession.close();}}/** * 继承PageParams的参数传递. */public static void testInherit() {logger.info("#################测试分页参数以继承PageParams形式传递###########################");SqlSession sqlSession = null;try {sqlSession = MyBatisUtil.getSqlSessionFactroy().openSession();RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);TestParams params = new TestParams();params.setUseFlag(true);params.setCheckFlag(false);params.setPage(2);params.setPageSize(5);params.setRoleName("test");roleMapper.selectAllRole(params);logger.info("总条数==>" + params.getTotal());logger.info("总页数 ==>" + params.getTotalPage());} finally {sqlSession.close();}}/** * 使用map方式。(map的键随意取) */public static void testMap() {logger.info("#################测试分页参数以Map形式传递###########################");SqlSession sqlSession = null;try {sqlSession = MyBatisUtil.getSqlSessionFactroy().openSession();RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);Map<String, Object> paramMap = new HashMap<String, Object>();PageParams pageParams = new PageParams();pageParams.setUseFlag(true);pageParams.setCheckFlag(false);pageParams.setPage(2);pageParams.setPageSize(5);paramMap.put("roleName", "test");paramMap.put("page_drsdsd2233", pageParams);roleMapper.selectRoleByMap(paramMap);logger.info("总条数==>" + pageParams.getTotal());logger.info("总页数 ==>" + pageParams.getTotalPage());} finally {sqlSession.close();}}/** * 使用MyBatis  @Param注解 传递参数. */public static void testAtParam() {logger.info("#################测试分页参数以@Param形式传递###########################");SqlSession sqlSession = null;try {sqlSession = MyBatisUtil.getSqlSessionFactroy().openSession();RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);PageParams pageParams2 = new PageParams();pageParams2.setUseFlag(true);pageParams2.setCheckFlag(true);pageParams2.setPage(2);pageParams2.setPageSize(5);pageParams2.setCleanOrderBy(true);roleMapper.selectRoleByMap2("test", pageParams2);logger.info("总条数==>" + pageParams2.getTotal());logger.info("总页数 ==>" + pageParams2.getTotalPage());} finally {sqlSession.close();}}/** * 使用POJO传递,但是POJO内部有一个PageParams属性,和它的setter方法. */public static void testPojoProperty() {logger.info("#################测试分页参数作为参数属性传递###########################");SqlSession sqlSession = null;try {sqlSession = MyBatisUtil.getSqlSessionFactroy().openSession();RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);PageParams pageParams3 = new PageParams();pageParams3.setUseFlag(true);pageParams3.setCheckFlag(false);pageParams3.setPage(3);pageParams3.setPageSize(5);pageParams3.setCleanOrderBy(true);TestParams2 p2 = new TestParams2();p2.setPageParams(pageParams3);p2.setRoleName("test");roleMapper.selectAllRole2(p2);logger.info("总条数==>" + pageParams3.getTotal());logger.info("总页数 ==>" + pageParams3.getTotalPage());} finally {sqlSession.close();}}}

测试的结果如下(我这里使用mysql也可以使用oracle,我也有测试过的):

 INFO 2016-06-23 21:02:37,966 com.learn.mybatis.chapter1.main.MyBatisExample: #################测试没有分页参数的查询###########################DEBUG 2016-06-23 21:02:38,169 org.apache.ibatis.logging.LogFactory: Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter.DEBUG 2016-06-23 21:02:38,186 org.apache.ibatis.datasource.pooled.PooledDataSource: PooledDataSource forcefully closed/removed all connections.DEBUG 2016-06-23 21:02:38,186 org.apache.ibatis.datasource.pooled.PooledDataSource: PooledDataSource forcefully closed/removed all connections.DEBUG 2016-06-23 21:02:38,186 org.apache.ibatis.datasource.pooled.PooledDataSource: PooledDataSource forcefully closed/removed all connections.DEBUG 2016-06-23 21:02:38,186 org.apache.ibatis.datasource.pooled.PooledDataSource: PooledDataSource forcefully closed/removed all connections.DEBUG 2016-06-23 21:02:38,267 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Opening JDBC ConnectionDEBUG 2016-06-23 21:02:38,470 org.apache.ibatis.datasource.pooled.PooledDataSource: Created connection 103887628.DEBUG 2016-06-23 21:02:38,470 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]DEBUG 2016-06-23 21:02:38,485 org.apache.ibatis.datasource.pooled.PooledDataSource: Created connection 1752203484.DEBUG 2016-06-23 21:02:38,486 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==>  Preparing: select id, role_name as roleName, note from t_role where id=? DEBUG 2016-06-23 21:02:38,508 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 1(Long)DEBUG 2016-06-23 21:02:38,532 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <==      Total: 0DEBUG 2016-06-23 21:02:38,533 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]DEBUG 2016-06-23 21:02:38,534 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]DEBUG 2016-06-23 21:02:38,535 org.apache.ibatis.datasource.pooled.PooledDataSource: Returned connection 103887628 to pool. INFO 2016-06-23 21:02:38,539 com.learn.mybatis.chapter1.main.MyBatisExample: #################测试分页参数以继承PageParams形式传递###########################DEBUG 2016-06-23 21:02:38,565 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Opening JDBC ConnectionDEBUG 2016-06-23 21:02:38,565 org.apache.ibatis.datasource.pooled.PooledDataSource: Checked out connection 103887628 from pool.DEBUG 2016-06-23 21:02:38,565 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]DEBUG 2016-06-23 21:02:38,575 org.apache.ibatis.datasource.pooled.PooledDataSource: Created connection 1682463303.DEBUG 2016-06-23 21:02:38,576 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==>  Preparing: select count(*) as total from (select id, role_name as roleName, note from t_role WHERE role_name like concat('%', ?, '%') order by id desc) $_paging DEBUG 2016-06-23 21:02:38,576 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: test(String)DEBUG 2016-06-23 21:02:38,577 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <==      Total: 1DEBUG 2016-06-23 21:02:38,577 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==>  Preparing: select * from (select id, role_name as roleName, note from t_role WHERE role_name like concat('%', ?, '%') order by id desc) $_paging_table limit ?, ? DEBUG 2016-06-23 21:02:38,579 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 5(Integer), 5(Integer), test(String)DEBUG 2016-06-23 21:02:38,583 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <==      Total: 5 INFO 2016-06-23 21:02:38,584 com.learn.mybatis.chapter1.main.MyBatisExample: 总条数==>10 INFO 2016-06-23 21:02:38,584 com.learn.mybatis.chapter1.main.MyBatisExample: 总页数 ==>2DEBUG 2016-06-23 21:02:38,584 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]DEBUG 2016-06-23 21:02:38,585 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]DEBUG 2016-06-23 21:02:38,585 org.apache.ibatis.datasource.pooled.PooledDataSource: Returned connection 103887628 to pool. INFO 2016-06-23 21:02:38,585 com.learn.mybatis.chapter1.main.MyBatisExample: #################测试分页参数以Map形式传递###########################DEBUG 2016-06-23 21:02:38,588 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Opening JDBC ConnectionDEBUG 2016-06-23 21:02:38,588 org.apache.ibatis.datasource.pooled.PooledDataSource: Checked out connection 103887628 from pool.DEBUG 2016-06-23 21:02:38,588 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]DEBUG 2016-06-23 21:02:38,601 org.apache.ibatis.datasource.pooled.PooledDataSource: Created connection 156545103.DEBUG 2016-06-23 21:02:38,601 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==>  Preparing: select count(*) as total from (select id, role_name as roleName, note from t_role WHERE role_name like concat('%', ?, '%') order by id desc) $_paging DEBUG 2016-06-23 21:02:38,602 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: test(String)DEBUG 2016-06-23 21:02:38,604 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <==      Total: 1DEBUG 2016-06-23 21:02:38,604 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==>  Preparing: select * from (select id, role_name as roleName, note from t_role WHERE role_name like concat('%', ?, '%') order by id desc) $_paging_table limit ?, ? DEBUG 2016-06-23 21:02:38,605 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 5(Integer), 5(Integer), test(String)DEBUG 2016-06-23 21:02:38,608 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <==      Total: 5 INFO 2016-06-23 21:02:38,609 com.learn.mybatis.chapter1.main.MyBatisExample: 总条数==>10 INFO 2016-06-23 21:02:38,609 com.learn.mybatis.chapter1.main.MyBatisExample: 总页数 ==>2DEBUG 2016-06-23 21:02:38,609 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]DEBUG 2016-06-23 21:02:38,610 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]DEBUG 2016-06-23 21:02:38,610 org.apache.ibatis.datasource.pooled.PooledDataSource: Returned connection 103887628 to pool. INFO 2016-06-23 21:02:38,610 com.learn.mybatis.chapter1.main.MyBatisExample: #################测试分页参数以@Param形式传递###########################DEBUG 2016-06-23 21:02:38,612 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Opening JDBC ConnectionDEBUG 2016-06-23 21:02:38,613 org.apache.ibatis.datasource.pooled.PooledDataSource: Checked out connection 103887628 from pool.DEBUG 2016-06-23 21:02:38,613 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]DEBUG 2016-06-23 21:02:38,627 org.apache.ibatis.datasource.pooled.PooledDataSource: Created connection 668210649.DEBUG 2016-06-23 21:02:38,627 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==>  Preparing: select count(*) as total from (select id, role_name as roleName, note from t_role) $_paging DEBUG 2016-06-23 21:02:38,628 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: DEBUG 2016-06-23 21:02:38,630 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <==      Total: 1DEBUG 2016-06-23 21:02:38,630 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==>  Preparing: select * from (select id, role_name as roleName, note from t_role) $_paging_table limit ?, ? DEBUG 2016-06-23 21:02:38,631 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 5(Integer), 5(Integer)DEBUG 2016-06-23 21:02:38,633 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <==      Total: 5 INFO 2016-06-23 21:02:38,634 com.learn.mybatis.chapter1.main.MyBatisExample: 总条数==>10 INFO 2016-06-23 21:02:38,634 com.learn.mybatis.chapter1.main.MyBatisExample: 总页数 ==>2DEBUG 2016-06-23 21:02:38,634 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]DEBUG 2016-06-23 21:02:38,635 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]DEBUG 2016-06-23 21:02:38,635 org.apache.ibatis.datasource.pooled.PooledDataSource: Returned connection 103887628 to pool. INFO 2016-06-23 21:02:38,635 com.learn.mybatis.chapter1.main.MyBatisExample: #################测试分页参数作为参数属性传递###########################DEBUG 2016-06-23 21:02:38,636 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Opening JDBC ConnectionDEBUG 2016-06-23 21:02:38,636 org.apache.ibatis.datasource.pooled.PooledDataSource: Checked out connection 103887628 from pool.DEBUG 2016-06-23 21:02:38,636 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]DEBUG 2016-06-23 21:02:38,643 org.apache.ibatis.datasource.pooled.PooledDataSource: Created connection 1361289747.DEBUG 2016-06-23 21:02:38,644 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==>  Preparing: select count(*) as total from (select id, role_name as roleName, note from t_role WHERE role_name like concat('%', ?, '%') ) $_paging DEBUG 2016-06-23 21:02:38,644 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: test(String)DEBUG 2016-06-23 21:02:38,645 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <==      Total: 1DEBUG 2016-06-23 21:02:38,645 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==>  Preparing: select * from (select id, role_name as roleName, note from t_role WHERE role_name like concat('%', ?, '%') order by id desc) $_paging_table limit ?, ? DEBUG 2016-06-23 21:02:38,646 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 10(Integer), 5(Integer), test(String)DEBUG 2016-06-23 21:02:38,648 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <==      Total: 0 INFO 2016-06-23 21:02:38,648 com.learn.mybatis.chapter1.main.MyBatisExample: 总条数==>10 INFO 2016-06-23 21:02:38,648 com.learn.mybatis.chapter1.main.MyBatisExample: 总页数 ==>2DEBUG 2016-06-23 21:02:38,648 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]DEBUG 2016-06-23 21:02:38,649 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]DEBUG 2016-06-23 21:02:38,649 org.apache.ibatis.datasource.pooled.PooledDataSource: Returned connection 103887628 to pool.


此时为了测试验证页码的和去掉order by语句的效果,我们再把testPojoProperty()方法修改一下:

/** * 使用POJO传递,但是POJO内部有一个PageParams属性,和它的setter方法. */public static void testPojoProperty() {logger.info("#################测试分页参数作为参数属性传递###########################");SqlSession sqlSession = null;try {sqlSession = MyBatisUtil.getSqlSessionFactroy().openSession();RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);PageParams pageParams3 = new PageParams();pageParams3.setUseFlag(true);pageParams3.setCheckFlag(true);//检验页码的有效性。pageParams3.setPage(6);//超过最大页数pageParams3.setPageSize(5);pageParams3.setCleanOrderBy(false);//不去掉order by 语句TestParams2 p2 = new TestParams2();p2.setPageParams(pageParams3);p2.setRoleName("test");roleMapper.selectAllRole2(p2);logger.info("总条数==>" + pageParams3.getTotal());logger.info("总页数 ==>" + pageParams3.getTotalPage());} finally {sqlSession.close();}}

再运行一下,得到日志:

  INFO 2016-06-23 21:09:09,643 com.learn.mybatis.chapter1.main.MyBatisExample: #################测试分页参数作为参数属性传递###########################DEBUG 2016-06-23 21:09:09,839 org.apache.ibatis.logging.LogFactory: Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter.DEBUG 2016-06-23 21:09:09,856 org.apache.ibatis.datasource.pooled.PooledDataSource: PooledDataSource forcefully closed/removed all connections.DEBUG 2016-06-23 21:09:09,856 org.apache.ibatis.datasource.pooled.PooledDataSource: PooledDataSource forcefully closed/removed all connections.DEBUG 2016-06-23 21:09:09,856 org.apache.ibatis.datasource.pooled.PooledDataSource: PooledDataSource forcefully closed/removed all connections.DEBUG 2016-06-23 21:09:09,857 org.apache.ibatis.datasource.pooled.PooledDataSource: PooledDataSource forcefully closed/removed all connections.DEBUG 2016-06-23 21:09:09,957 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Opening JDBC ConnectionDEBUG 2016-06-23 21:09:10,166 org.apache.ibatis.datasource.pooled.PooledDataSource: Created connection 142555199.DEBUG 2016-06-23 21:09:10,166 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@87f383f]DEBUG 2016-06-23 21:09:10,181 org.apache.ibatis.datasource.pooled.PooledDataSource: Created connection 192794887.DEBUG 2016-06-23 21:09:10,182 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==>  Preparing: select count(*) as total from (select id, role_name as roleName, note from t_role WHERE role_name like concat('%', ?, '%') order by id desc) $_paging DEBUG 2016-06-23 21:09:10,218 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: test(String)DEBUG 2016-06-23 21:09:10,243 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <==      Total: 1DEBUG 2016-06-23 21:09:10,245 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@87f383f]DEBUG 2016-06-23 21:09:10,245 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@87f383f]DEBUG 2016-06-23 21:09:10,246 org.apache.ibatis.datasource.pooled.PooledDataSource: Returned connection 142555199 to pool.Exception in thread "main" org.apache.ibatis.exceptions.PersistenceException: ### Error querying database.  Cause: java.lang.reflect.UndeclaredThrowableException### The error may exist in com\learn\mybatis\chapter1\sqlmap\role.xml### The error may involve com.learn.mybatis.chapter1.mapper.RoleMapper.selectAllRole2-Inline### The error occurred while setting parameters### Cause: java.lang.reflect.UndeclaredThrowableException    at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:26)    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:111)    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:102)    at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:119)    at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:63)    at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:52)    at com.sun.proxy.$Proxy4.selectAllRole2(Unknown Source)    at com.learn.mybatis.chapter1.main.MyBatisExample.testPojoProperty(MyBatisExample.java:131)    at com.learn.mybatis.chapter1.main.MyBatisExample.main(MyBatisExample.java:23)Caused by: java.lang.reflect.UndeclaredThrowableException    at com.sun.proxy.$Proxy5.prepare(Unknown Source)    at org.apache.ibatis.executor.SimpleExecutor.prepareStatement(SimpleExecutor.java:73)    at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:59)    at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:267)    at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:137)    at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:96)    at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:77)    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:108)    ... 7 moreCaused by: java.lang.Exception: 查询失败,查询页码【6】大于总总页【2】!!    at com.learn.mybatis.plugin.PagingPlugin.checkPage(PagingPlugin.java:168)    at com.learn.mybatis.plugin.PagingPlugin.intercept(PagingPlugin.java:99)    at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:60)    ... 15 more


说明页码超过了最大的页数,注意这里的因为有了这句:pageParams3.setCleanOrderBy(false);所以从日志可以看出,和上次不太一样,插件没有帮我们去掉了影响性能的order by语句。这些都是可以通过参数由你来控制的。当然使用默认的参数也是可以的。








3 0
原创粉丝点击