Mybatis拦截器实现分页和存储过程实现分页

来源:互联网 发布:wifi mac地址查询 编辑:程序博客网 时间:2024/06/07 02:46

Mybatis拦截器和存储过程的数据库分页

1.1 Mybatis拦截器实现分页

主要思路:Mybatis拦截器常常会被用来进行分页处理。我们知道要利用JDBC对数据库进行操作就必须要有一个对应的Statement对象,Mybatis在执行Sql语句前也会产生一个包含Sql语句的Statement对象,而且对应的Sql语句是在Statement之前产生的,所以我们就可以在它成Statement之前对用来生成Statement的Sql语句下手。在Mybatis中Statement语句是通过RoutingStatementHandler对象的prepare方法生成的。所以利用拦截器实现Mybatis分页的一个思路就是拦截StatementHandler接口的prepare方法,然后在拦截器方法中把Sql语句改成对应的分页查询Sql语句,之后再调用StatementHandler对象的prepare方法,即调用invocation.proceed()。更改Sql语句这个看起来很简单,而事实上来说的话就没那么直观,因为包括sql等其他属性在内的多个属性都没有对应的方法可以直接取到,它们对外部都是封闭的,是对象的私有属性,所以这里就需要引入反射机制来获取或者更改对象的私有属性的值了。对于分页而言,在拦截器里面我们常常还需要做的一个操作就是统计满足当前条件的记录一共有多少,这是通过获取到了原始的Sql语句后,把它改为对应的统计语句再利用Mybatis封装好的参数和设置参数的功能把Sql语句中的参数进行替换,之后再执行查询记录数的Sql语句进行总记录数的统计。

用到的文件:Page实体 PagePlugin实现拦截器的分页插件 ReflectHelper 反射工具类

 

1.2 具体代码及说明

Page实体:

packagemain.java.com.jt.core.util;



import java.util.ArrayList;
import java.util.List;

/**
 * 分页类
 */
public class Page<T> {
   
   privateInteger page=1;//当前页码
   privateInteger pagesize=20;//每页显示条数
   privateInteger total;//总数
   privateInteger from;//起始索引
   privateInteger to;//结束索引
   privateList<T>Rows =new ArrayList<T>();
   publicList getCommonList() {
      returncommonList;
   }

   public voidsetCommonList(ListcommonList) {
      this.commonList= commonList;
   }

   privateList<T>   commonList= newArrayList<T>();//通用集合,用于多条件查询
   private booleanentityOrField;//true:需要分页的地方,传入的参数就是Page实体;false:需要分页的地方,传入的参数所代表的实体拥有Page属性
   privateString keywords;
   privateString pid;

   publicInteger getPage() {
      returnpage;
   }
   public voidsetPage(Integerpage) {
      this.page= page;
   }
   publicInteger getPagesize() {
      returnpagesize;
   }
   public voidsetPagesize(Integerpagesize) {
      this.pagesize= pagesize;
   }
   publicInteger getTotal() {
      returntotal;
   }
   public voidsetTotal(Integertotal) {
      this.total= total;
   }
   publicInteger getFrom() {
      return(this.page-1)*this.pagesize+1;
   }
   public voidsetFrom(Integerfrom) {
      this.from= from;
   }
   publicInteger getTo() {
      return this.page*this.pagesize;
   }
   public voidsetTo(Integerto) {
      this.to= to;
   }
   publicList<T>getRows() {
      returnRows;
   }
   public voidsetRows(List<T>rows) {
      Rows= rows;
   }
   public booleanisEntityOrField() {
      returnentityOrField;
   }
   public voidsetEntityOrField(booleanentityOrField) {
      this.entityOrField= entityOrField;
   }

   publicString getKeywords() {
      returnkeywords;
   }

   public voidsetKeywords(Stringkeywords) {
      this.keywords= keywords;
   }

   publicString getPid() {
      returnpid;
   }

   public voidsetPid(Stringpid) {
      this.pid= pid;
   }
}

目前用到的page实体属性有4个 需要传入的属性2

用到的属性 page pagesize total entityOrField需要传入 page pagesize (有默认值)

 

ReflectHelper 类:

packagemain.java.com.jt.core.util;

import java.lang.reflect.Field;

/**
 * 说明:反射工具
 */
public class ReflectHelper{
   /**
    * 获取obj对象fieldName的Field
    * @param obj
    *@param fieldName
    *@return
    */
   public staticField getFieldByFieldName(Objectobj,String fieldName) {
      for(Class<?>superClass =obj.getClass();superClass !=Object.class;superClass =superClass
            .getSuperclass()) {
         try{
            returnsuperClass.getDeclaredField(fieldName);//获取class的所有字段
         }catch (NoSuchFieldExceptione) {
         }
      }
      return null;
   }

   /**
    * 获取obj对象fieldName的属性值
    * @param obj
    *@param fieldName
    *@return
    *@throws SecurityException
    
*@throws NoSuchFieldException
    
*@throws IllegalArgumentException
    
*@throws IllegalAccessException
    
*/
   public staticObject getValueByFieldName(Objectobj,String fieldName)
         throwsSecurityException,NoSuchFieldException,
         IllegalArgumentException,IllegalAccessException {
      Fieldfield =getFieldByFieldName(obj,fieldName);
      Objectvalue =null;
      if(field!=null){
         if(field.isAccessible()) {
            value= field.get(obj);
         } else{
            field.setAccessible(true);
            value= field.get(obj);
            field.setAccessible(false);
         }
      }
      returnvalue;
   }

   /**
    * 设置obj对象fieldName的属性值
    * @param obj
    *@param fieldName
    *@param value
    *@throws SecurityException
    
*@throws NoSuchFieldException
    
*@throws IllegalArgumentException
    
*@throws IllegalAccessException
    
*/
   public static voidsetValueByFieldName(Objectobj,String fieldName,
         Objectvalue)throws SecurityException,NoSuchFieldException,
         IllegalArgumentException,IllegalAccessException {
      Fieldfield =obj.getClass().getDeclaredField(fieldName);
      if(field.isAccessible()) {
         field.set(obj,value);
      } else{
         field.setAccessible(true);
         field.set(obj,value);
         field.setAccessible(false);
      }
   }
}

 

说明:反射获取class的所有私有属性 因为Mybatisprepare方法的所有属性都是私有的 没有对外提供getset方法 只能通过运行过程中反射取到和修改属性的值。

PagePlugin 类:

packagemain.java.com.jt.core.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.Properties;

import javax.xml.bind.PropertyException;

import org.apache.ibatis.executor.ErrorContext;
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.scripting.xmltags.ForEachSqlNode;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;


/**
 *
* 类名称:分页插件
 */
@Intercepts({@Signature(type=StatementHandler.class,method="prepare",args={Connection.class})})
public class PagePluginimplements Interceptor{

   private staticString dialect= "";    //数据库方言
   private staticString pageSqlId= "";//mapper.xml中需要拦截的ID(正则匹配)

   //对于StatementHandler其实只有两个实现类,一个是RoutingStatementHandler,另一个是抽象类BaseStatementHandler,
   //BaseStatementHandler有三个子类,分别是SimpleStatementHandler,PreparedStatementHandler和CallableStatementHandler,
   //SimpleStatementHandler是用于处理Statement的,PreparedStatementHandler是处理PreparedStatement的,而CallableStatementHandler是
   //处理CallableStatement的。Mybatis在进行Sql语句处理的时候都是建立的RoutingStatementHandler,而在RoutingStatementHandler里面拥有一个
   //StatementHandler类型的delegate属性,RoutingStatementHandler会依据Statement的不同建立对应的BaseStatementHandler,即SimpleStatementHandler、
   //PreparedStatementHandler或CallableStatementHandler,在RoutingStatementHandler里面所有StatementHandler接口方法的实现都是调用的delegate对应的方法。
   //我们在PageInterceptor类上已经用@Signature标记了该Interceptor只拦截StatementHandler接口的prepare方法,又因为Mybatis只有在建立RoutingStatementHandler的时候
   //是通过Interceptor的plugin方法进行包裹的,所以我们这里拦截到的目标对象肯定是RoutingStatementHandler对象。
   publicObject intercept(Invocationivk)throws Throwable{
      //TODO Auto-generated method stub
      
if(ivk.getTarget()instanceof RoutingStatementHandler){
         RoutingStatementHandlerstatementHandler = (RoutingStatementHandler)ivk.getTarget();
         BaseStatementHandlerdelegate = (BaseStatementHandler)ReflectHelper.getValueByFieldName(statementHandler,"delegate");
         //通过反射获取delegate父类BaseStatementHandler的mappedStatement属性
         MappedStatementmappedStatement = (MappedStatement)ReflectHelper.getValueByFieldName(delegate,"mappedStatement");
         
         if(mappedStatement.getId().matches(pageSqlId)){//拦截需要分页的SQL
            BoundSqlboundSql =delegate.getBoundSql();
            ObjectparameterObject =boundSql.getParameterObject();//分页SQL<select>中parameterType属性对应的实体参数,即Mapper接口中执行分页方法的参数,该参数不得为空
            if(parameterObject==null){
               throw newNullPointerException("parameterObject尚未实例化!");
            }else{
               //拦截到的prepare方法参数是一个Connection对象
               Connectionconnection = (Connection)ivk.getArgs()[0];
               //获取当前要执行的Sql语句,也就是我们直接在Mapper映射语句中写的Sql语句
               Stringsql =boundSql.getSql();
               //String countSql = "select count(0) from (" + sql+ ") as tmp_count"; //记录统计
               Stringfhsql =sql;
               StringcountSql ="select count(0) from ("+ fhsql+")  tmp_count";//记录统计 == oracle 加 as 报错(SQL command not properly ended)
               //通过connection建立一个countSql对应的PreparedStatement对象。
               PreparedStatementcountStmt =connection.prepareStatement(countSql);
               BoundSqlcountBS =new BoundSql(mappedStatement.getConfiguration(),countSql,boundSql.getParameterMappings(),parameterObject);
               //通过parameterHandler给PreparedStatement对象设置参数
               setParameters(countStmt,mappedStatement,countBS,parameterObject);
               //之后就是执行获取总记录数的Sql语句和获取结果了。
               ResultSetrs =countStmt.executeQuery();
               intcount =0;
               if(rs.next()) {
                  count= rs.getInt(1);
               }
               rs.close();
               countStmt.close();
               //System.out.println(count);
               Pagepage =null;
               if(parameterObjectinstanceof Page){   //参数就是Page实体
                   page= (Page)parameterObject;
                   page.setEntityOrField(true);   
                   page.setTotal(count);
               }else{//参数为某个实体,该实体拥有Page属性
                  FieldpageField =ReflectHelper.getFieldByFieldName(parameterObject,"page");
                  if(pageField!=null){
                     page= (Page)ReflectHelper.getValueByFieldName(parameterObject,"page");
                     if(page==null)
                        page= newPage();
                     page.setEntityOrField(false);
                      page.setTotal(count);
                     ReflectHelper.setValueByFieldName(parameterObject,"page",page);//通过反射,对实体对象设置分页对象
                  }else{
                     throw newNoSuchFieldException(parameterObject.getClass().getName()+"不存在 page 属性!");
                  }
               }
               //获取分页Sql语句
               StringpageSql =generatePageSql(sql,page);
               //利用反射设置当前BoundSql对应的sql属性为我们建立好的分页Sql语句
               ReflectHelper.setValueByFieldName(boundSql,"sql",pageSql);//将分页sql语句反射回BoundSql.
            }
         }
      }
      returnivk.proceed();
   }

   
   /**
    * 对SQL参数(?)设值,参考org.apache.ibatis.executor.parameter.DefaultParameterHandler
    * @param ps
    *@param mappedStatement
    *@param boundSql
    *@param parameterObject
    *@throws SQLException
    
*/
   private voidsetParameters(PreparedStatementps,MappedStatementmappedStatement,BoundSqlboundSql,ObjectparameterObject)throws SQLException{
      //获取对应的BoundSql,这个BoundSql其实跟我们利用StatementHandler获取到的BoundSql是同一个对象。
      //delegate里面的boundSql也是通过mappedStatement.getBoundSql(paramObj)方法获取到的。
      ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
      //通过BoundSql获取对应的参数映射
      List<ParameterMapping>parameterMappings =boundSql.getParameterMappings();
      if(parameterMappings!= null) {
         Configurationconfiguration =mappedStatement.getConfiguration();
         TypeHandlerRegistrytypeHandlerRegistry =configuration.getTypeHandlerRegistry();
         MetaObjectmetaObject =parameterObject ==null ?null:configuration.newMetaObject(parameterObject);
         for(inti =0;i <parameterMappings.size();i++) {
            ParameterMappingparameterMapping =parameterMappings.get(i);
            if(parameterMapping.getMode() != ParameterMode.OUT) {
               Objectvalue;
               StringpropertyName =parameterMapping.getProperty();
               PropertyTokenizerprop =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);
               }
               TypeHandlertypeHandler =parameterMapping.getTypeHandler();
               if(typeHandler== null) {
                  throw newExecutorException("There was no TypeHandler found for parameter "+propertyName +" of statement "+mappedStatement.getId());
               }
               typeHandler.setParameter(ps,i +1,value,parameterMapping.getJdbcType());
            }
         }
      }
   }
   
   /**
    * 根据数据库方言,生成特定的分页sql
    * @param sql
    *@param page
    *@return
    */
   privateString generatePageSql(Stringsql,Pagepage){
      if(page!=null&& Tools.notEmpty(dialect)){
         StringBufferpageSql =new StringBuffer();
         if("mysql".equals(dialect)){
            pageSql.append(sql);
            pageSql.append(" limit "+(page.getPage()-1)*page.getPagesize()+","+page.getPagesize());
         }else if("oracle".equals(dialect)){
            //计算第一条记录的位置,Oracle分页是通过rownum进行的,而rownum是从1开始的
            intoffset = (page.getPage() - 1) *page.getPagesize() +1;
            pageSql.insert(0,"select u.*, rownum r from (").append(") u where rownum < ").append(offset+ page.getPagesize());
            pageSql.insert(0,"select * from (").append(") where r >= ").append(offset);
            //上面的Sql语句拼接之后大概是这个样子:
            //select * from (select u.*, rownum r from (select * from t_user) u where rownum < 31) where r >= 16
         }
         returnpageSql.toString();
      }else{
         returnsql;
      }
   }

   /**
    * 最先进入的方法
    * @param arg0
    *@return
    */
   publicObject plugin(Objectarg0) {
      //TODO Auto-generated method stub
      
returnPlugin.wrap(arg0,this);
   }

   public voidsetProperties(Propertiesp) {
      dialect= p.getProperty("dialect");
      if(isEmpty(dialect)) {
         try{
            throw newPropertyException("dialect property is not found!");
         } catch(PropertyExceptione) {
            //TODO Auto-generated catch block
            
e.printStackTrace();
         }
      }
      pageSqlId= p.getProperty("pageSqlId");
      if(isEmpty(pageSqlId)) {
         try{
            throw newPropertyException("pageSqlId property is not found!");
         } catch(PropertyExceptione) {
            //TODO Auto-generated catch block
            
e.printStackTrace();
         }
      }
   }
   /**
    * 检测字符串是否为空(null,"","null")
    * @param s
    *@return 为空则返回true,不否则返回false
    */
   public static booleanisEmpty(Strings){
      returns==null|| "".equals(s) || "null".equals(s);
   }
   
}

 

具体说明都在注释中

1.3 补充说明

最好让这三个文件同包调用

配置数据库方言和拦截字段在Mybatis-configuration.xml 配置文件中

具体如下:

<plugins>
    <plugininterceptor="main.java.com.jt.core.util.PagePlugin">
        <propertyname="dialect"value="mysql"/>
        <propertyname="pageSqlId"value=".*test$"/>
    </plugin>
</plugins>

这个操作是注册拦截器

其中,dialect是数据库方言 现在支持mysqloracle两种数据库的分页pageSqlId是拦截的sql id匹配Mapper接口中的方法名 和Mapper.xml中的select id (使用正则匹配的方式 如例子中的贪婪匹配所有以test结尾的字段)

最后需要注意除了分页以外的其他数据库独有的写法需要避免。

1.4 实现例子

ZhaoBiaoMapper数据层接口的方法:

//测试mybatis拦截器
ArrayList<ZhaoBiao>zbpagetest(ZhaoBiaozhaoBiao);

映射的Mapper.xml中的实现:

<selectid="zbpagetest"parameterType="main.java.com.jt.bid.entity.ZhaoBiao"resultType="main.java.com.jt.bid.entity.ZhaoBiao">
    SELECT *FROM t_zb
</select>

业务层:

ArrayList<ZhaoBiao>listzb(ZhaoBiaozhaoBiao);

实现类:

@Override
public ArrayList<ZhaoBiao>listzb(ZhaoBiaozhaoBiao) {
    returnzhaoBiaoMapper.zbpagetest(zhaoBiao);
}

控制层:

@RequestMapping("/test")
@ResponseBody
public void test(){
    Pagepage =new Page();
    page.setPagesize(20);
    ZhaoBiaozhaoBiao =newZhaoBiao();
    zhaoBiao.setPage(page);
    ArrayList<ZhaoBiao>list= zhaoBiaoService.listzb(zhaoBiao);
    Integertotal =zhaoBiao.getPage().getTotal();

}

运行测试 结果:

 

如果没有条件查询的话 可以直接传入Page实体 也就是说替换zhaoBiao实体.

2.1 存储过程实现分页

具体思路:通过提前对数据库构造存储过程,然后传入必要的参数,实现程序中不出现数据库的关键字段。

2.2 高度优化的通用Mysql数据库分页存储过程

    usedatabasename;
delimiter $$
drop procedure if exists prc_page_result $$
create procedure prc_page_result(
in currpage      int,#起止页数
in columns       varchar(500),#查询字段 没有特殊条件的写"*"
in tablename     varchar(500),# 表名称
in sCondition    varchar(500),# 查询条件 就是where 不用写where 但是要写and 后期考虑是不是写成where 1=1 后面就直接加and
in order_field   varchar(100),# 排序的字段 一定要写 如果没有特殊要求直接写按主键排序 其他字段排序影响性能
in asc_field     int,#排序的顺序 1代表的是逆序 desc 其他的代表正序 asc 注意这里只能是int类型
in primary_fieldvarchar(100),# 主键 表格主键 必填 影响后面查询速度
in pagesize      int#一页显示数据的条数
)
begin
    declare
sTemp  varchar(1000);#初始化数据 需要的sql语句 下面两个作用相同
    declaresSql   varchar(4000);
    declaresOrder varchar(1000);
    
    ifasc_field =1 then# 排序是1的时候 反向排列
        setsOrder =concat(' order by ',order_field,' desc ');# 设置排序语句
        setsTemp  ='<(select min';# 逆序的时候查最小
    else
        set
sOrder= concat(' order by ',order_field,' asc ');# 正序的order语句
        setsTemp  ='>(select max';# 正序查最大
    end if;
    
    ifcurrpage =1 then# 第一页
        ifsCondition <>'' then# 查询条件不为空的时候
            setsSql =concat('select ',columns,' from ',tablename,' where ');# 拼接查询语句
            setsSql =concat(sSql,sCondition,sOrder,' limit ?');# select * from t_zz where 1=1 order by zjid limit
        else
            set
sSql= concat('select ',columns,' from ',tablename,sOrder,' limit ?');
        end if;
    else
        if
sCondition<> ''then
            set
sSql= concat('select ',columns,' from ',tablename);
            setsSql =concat(sSql,' where ',sCondition,' and ',primary_field,sTemp);# select * from t_zb where 1=1 and zbid<(select min
            setsSql =concat(sSql,'(',primary_field,')',' from (select ');# select * from t_zb where 1=1 and zbid<(select min(zbid) from (select
            setsSql =concat(sSql,' ',primary_field,' from ',tablename,sOrder);#select * from t_zb where 1=1 and zbid<(select min(zbid) from (select zbid from t_zb order by zjid desc
            setsSql =concat(sSql,' limit ', (currpage-1)*pagesize,') as tabtemp)',sOrder);#select * from t_zb where 1=1 and zbid<(select min(zbid) from (select zbid from t_zb order by zjid desc limit 20) as tabtemp) order by zbid desc
            setsSql =concat(sSql,' limit ?');#select * from t_zb where 1=1 and zbid<(select min(zbid) from (select zbid from t_zb order by zjid desc limit 20) as tabtemp) order by zbid desc limit ?
        else
            set
sSql= concat('select ',columns,' from ',tablename);
            setsSql =concat(sSql,' where ',primary_field,sTemp);
            setsSql =concat(sSql,'(',primary_field,')',' from (select ');
            setsSql =concat(sSql,' ',primary_field,' from ',tablename,sOrder);
            setsSql =concat(sSql,' limit ', (currpage-1)*pagesize,') as tabtemp)',sOrder);
            setsSql =concat(sSql,' limit ?');
        end if;
    end if;
    set@iPageSize =pagesize;# 设置动态数据
    set@sQuery =sSql;# 查询语句
    preparestmt from@sQuery;# 预查询
    executestmt using@iPageSize;#动态塞入参数  mysql5.1版本以前不支持
end;
$$
delimiter ;

 

解析出来:

 

需要提前在数据库命令符界面 复制代码并输入这段存储过程

使用Mybatis进行操作:

数据层接口:

ArrayList<ZhaoBiao>cqgc(HashMapmap);

映射:

<selectid="cqgc"statementType="CALLABLE"parameterType="HashMap"resultType="main.java.com.jt.bid.entity.ZhaoBiao">
    call prc_page_result(
    #{currpage,jdbcType=INTEGER,mode = IN},
    #{columns,jdbcType=VARCHAR,mode =IN},
    #{tablename,jdbcType=VARCHAR,mode = IN},
    #{sCondition,jdbcType=VARCHAR,mode = IN},
    #{order_field,jdbcType=VARCHAR, mode = IN},
    #{asc_field,jdbcType=INTEGER,mode=IN},
    #{primary_field,jdbcType = VARCHAR , mode =IN},
    #{pagesize,jdbcType = INTEGER , mode =IN}
    )
</select>

业务层:

Integerocunttest();//前面返回参数没有意义,仅仅测试

实现类:

@Override
public Integerocunttest() {
    HashMapmap =new HashMap();
    map.put("currpage",1);
    map.put("columns","*");
    map.put("tablename","t_zb");
    map.put("sCondition","");
    map.put("order_field","zbid");
    map.put("asc_field",1);
    map.put("primary_field","zbid");
    map.put("pagesize",20);
    ArrayList<ZhaoBiao>list =zhaoBiaoMapper.cqgc(map);
    System.out.println(list.toArray());
    return null;
}

控制层:

@RequestMapping("/test1")
@ResponseBody
public void tese1(){
    zhaoBiaoService.ocunttest();
}

测试结果:

 

2.3 简化后的通用Mysql存储过程

    use databasename;
delimiter $$
drop procedure if exists prc_page_onetable $$
create procedure prc_page_onetable(
in currpage      int,#起止页数
in columns       varchar(500),#查询字段 没有特殊条件的写"*"
in tablename     varchar(500),# 表名称
in sCondition    varchar(500),# 查询条件 就是where 不用写where 但是要写and 后期考虑是不是写成where 1=1 后面就直接加and
in order_field   varchar(100),# 排序的字段 一定要写 如果没有特殊要求直接写按主键排序 其他字段排序影响性能
in pagesize      int#一页显示数据的条数
)
begin
    declare
sSql   varchar(4000);
    

        ifsCondition <>'' then
            set
sSql= concat('select ',columns,' from ',tablename);
            setsSql =concat(sSql,' where ',sCondition);
            setsSql =concat(sSql,' ',order_field,' limit ',(currpage-1)*pagesize,',',pagesize);
        else
            set
sSql= concat('select ',columns,' from ',tablename);
            setsSql =concat(sSql,' ',order_field,' limit ',(currpage-1)*pagesize,',',pagesize);
    end if;
    set@sQuery =sSql;# 查询语句
    preparestmt from@sQuery;# 预查询
    executestmt ;
end;
$$
delimiter ;

 

Mapper接口中的方法:

ArrayList<ZhaoBiao>cqgcforone(HashMapmap);

映射:

<selectid="cqgcforone"statementType="CALLABLE"parameterType="HashMap"resultType="main.java.com.jt.bid.entity.ZhaoBiao">
    call prc_page_onetable(
            #{currpage,jdbcType=INTEGER,mode = IN},
            #{columns,jdbcType=VARCHAR,mode =IN},
            #{tablename,jdbcType=VARCHAR,mode = IN},
            #{sCondition,jdbcType=VARCHAR,mode = IN},
            #{order_field,jdbcType=VARCHAR, mode = IN},
            #{pagesize,jdbcType = INTEGER , mode =IN}
    )
</select>

业务层:

voidccgc();

实现类:

@Override
public void ccgc() {
    Stringmc ="b";
    HashMapmap =new HashMap();
    map.put("currpage",1);
    map.put("columns","*");
    map.put("tablename","t_zb");
    map.put("sCondition","mc like CONCAT('%','"+mc+"','%')");
    map.put("order_field","");
    map.put("pagesize",20);
    ArrayListlist =zhaoBiaoMapper.cqgcforone(map);
    System.out.println(list.toArray());
}

测试结果:(控制层和上面的存储过程的类似)


最后总结 放上去的项目是一个没有被使用的项目作为演示 

两种分页方式呢 个人认为 拦截器的应用可能会更加适合现在的行情 现在的很多思路都是做成拦截器 像现在很火的权限框架shiro 内部也需要根据业务去实现很多自定义的拦截器

而关于存储过程 个人认为可以将大数据的优化sql写成存储过程 这样也可以减少人力的投入 也实现了sql 的复用

原创粉丝点击