Mybatis拦截器实现分页和存储过程实现分页
2017-12-12 16:53
405 查看
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实体:package
main.java.com.jt.core.util;
import java.util.ArrayList;
import java.util.List;
/**
* 分页类
*/
public class Page<T>
{
private
Integer page=1;//当前页码
private
Integer pagesize=20;//每页显示条数
private
Integer total;//总数
private
Integer from;//起始索引
private
Integer to;//结束索引
private
List<T>
Rows =
new ArrayList<T>();
public
List getCommonList() {
return
commonList;
}
public void
setCommonList(List
commonList) {
this.commonList
= commonList;
}
private
List<T> commonList
= new
ArrayList<T>();//通用集合,用于多条件查询
private boolean
entityOrField;
//true:需要分页的地方,传入的参数就是Page实体;false:需要分页的地方,传入的参数所代表的实体拥有Page属性
private
String keywords;
private
String pid;
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
Integer getTotal() {
return
total;
}
public void
setTotal(Integer
total) {
this.total
= total;
}
public
Integer getFrom() {
return
(this.page-1)*this.pagesize+1;
}
public void
setFrom(Integer
from) {
this.from
= from;
}
public
Integer getTo() {
return this.page*this.pagesize;
}
public void
setTo(Integer
to) {
this.to
= to;
}
public
List<T>
getRows() {
return
Rows;
}
public void
setRows(List<T>
rows) {
Rows
= rows;
}
public boolean
isEntityOrField() {
return
entityOrField;
}
public void
setEntityOrField(boolean
entityOrField) {
this.entityOrField
= entityOrField;
}
public
String getKeywords() {
return
keywords;
}
public void
setKeywords(String
keywords) {
this.keywords
= keywords;
}
public
String getPid() {
return
pid;
}
public void
setPid(String
pid) {
this.pid
= pid;
}
}
目前用到的page实体属性有4个 需要传入的属性2个
用到的属性 :page pagesize total entityOrField
需要传入 page pagesize (有默认值)
ReflectHelper 类:
package
main.java.com.jt.core.util;
import java.lang.reflect.Field;
/**
* 说明:反射工具
*/
public class ReflectHelper
{
/**
* 获取obj对象fieldName的Field
* @param obj
*
@param fieldName
*
@return
*/
public static
Field getFieldByFieldName(Object
obj,
String fieldName) {
for
(Class<?>
superClass =
obj.getClass();
superClass !=
Object.class;
superClass =
superClass
.getSuperclass()) {
try
{
return
superClass.getDeclaredField(fieldName);//获取class的所有字段
}
catch (NoSuchFieldException
e) {
}
}
return null;
}
/**
* 获取obj对象fieldName的属性值
* @param obj
*
@param fieldName
*
@return
*
@throws SecurityException
*
@throws NoSuchFieldException
*
@throws IllegalArgumentException
*
@throws IllegalAccessException
*/
public static
Object getValueByFieldName(Object
obj,
String fieldName)
throws
SecurityException,
NoSuchFieldException,
IllegalArgumentException,
IllegalAccessException
{
Field
field =
getFieldByFieldName(obj,
fieldName);
Object
value =
null;
if(field!=null){
if
(field.isAccessible()) {
value
= field.get(obj);
} else
{
field.setAccessible(true);
value
= field.get(obj);
field.setAccessible(false);
}
}
return
value;
}
/**
* 设置obj对象fieldName的属性值
* @param obj
*
@param fieldName
*
@param value
*
@throws SecurityException
*
@throws NoSuchFieldException
*
@throws IllegalArgumentException
*
@throws IllegalAccessException
*/
public static void
setValueByFieldName(Object
obj,
String fieldName,
Object
value)
throws SecurityException,
NoSuchFieldException,
IllegalArgumentException,
IllegalAccessException
{
Field
field =
obj.getClass().getDeclaredField(fieldName);
if
(field.isAccessible()) {
field.set(obj,
value);
} else
{
field.setAccessible(true);
field.set(obj,
value);
field.setAccessible(false);
}
}
}
说明:反射获取class的所有私有属性 因为Mybatis的prepare方法的所有属性都是私有的
没有对外提供get和set方法 只能通过运行过程中反射取到和修改属性的值。
PagePlugin 类:
package
main.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 PagePlugin
implements Interceptor
{
private static
String dialect
= ""; //数据库方言
private static
String 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对象。
public
Object intercept(Invocation
ivk)
throws Throwable
{
//
TODO Auto-generated method stub
if(ivk.getTarget()
instanceof RoutingStatementHandler){
RoutingStatementHandler
statementHandler = (RoutingStatementHandler)ivk.getTarget();
BaseStatementHandler
delegate = (BaseStatementHandler)
ReflectHelper.getValueByFieldName(statementHandler,
"delegate");
//通过反射获取delegate父类BaseStatementHandler的mappedStatement属性
MappedStatement
mappedStatement = (MappedStatement)
ReflectHelper.getValueByFieldName(delegate,
"mappedStatement");
if(mappedStatement.getId().matches(pageSqlId)){
//拦截需要分页的SQL
BoundSql
boundSql =
delegate.getBoundSql();
Object
parameterObject =
boundSql.getParameterObject();//分页SQL<select>中parameterType属性对应的实体参数,即Mapper接口中执行分页方法的参数,该参数不得为空
if(parameterObject==null){
throw new
NullPointerException("parameterObject尚未实例化!");
}else{
//拦截到的prepare方法参数是一个Connection对象
Connection
connection = (Connection)
ivk.getArgs()[0];
//获取当前要执行的Sql语句,也就是我们直接在Mapper映射语句中写的Sql语句
String
sql =
boundSql.getSql();
//String countSql = "select count(0) from (" + sql+ ") as tmp_count"; //记录统计
String
fhsql =
sql;
String
countSql =
"select count(0) from ("
+ fhsql+
") tmp_count";
//记录统计 == oracle 加 as 报错(SQL command not properly ended)
//通过connection建立一个countSql对应的PreparedStatement对象。
PreparedStatement
countStmt =
connection.prepareStatement(countSql);
BoundSql
countBS =
new BoundSql(mappedStatement.getConfiguration(),countSql,boundSql.getParameterMappings(),parameterObject);
//通过parameterHandler给PreparedStatement对象设置参数
setParameters(countStmt,mappedStatement,countBS,parameterObject);
//之后就是执行获取总记录数的Sql语句和获取结果了。
ResultSet
rs =
countStmt.executeQuery();
int
count =
0;
if
(rs.next()) {
count
= rs.getInt(1);
}
rs.close();
countStmt.close();
//System.out.println(count);
Page
page =
null;
if(parameterObject
instanceof Page){ //参数就是Page实体
page
= (Page)
parameterObject;
page.setEntityOrField(true);
page.setTotal(count);
}else{
//参数为某个实体,该实体拥有Page属性
Field
pageField =
ReflectHelper.getFieldByFieldName(parameterObject,"page");
if(pageField!=null){
page
= (Page)
ReflectHelper.getValueByFieldName(parameterObject,"page");
if(page==null)
page
= new
Page();
page.setEntityOrField(false);
page.setTotal(count);
ReflectHelper.setValueByFieldName(parameterObject,"page",
page);
//通过反射,对实体对象设置分页对象
}else{
throw new
NoSuchFieldException(parameterObject.getClass().getName()+"不存在
page 属性!");
}
}
//获取分页Sql语句
String
pageSql =
generatePageSql(sql,page);
//利用反射设置当前BoundSql对应的sql属性为我们建立好的分页Sql语句
ReflectHelper.setValueByFieldName(boundSql,
"sql",
pageSql);
//将分页sql语句反射回BoundSql.
}
}
}
return
ivk.proceed();
}
/**
* 对SQL参数(?)设值,参考org.apache.ibatis.executor.parameter.DefaultParameterHandler
* @param ps
*
@param mappedStatement
*
@param boundSql
*
@param parameterObject
*
@throws SQLException
*/
private void
setParameters(PreparedStatement
ps,MappedStatement
mappedStatement,BoundSql
boundSql,Object
parameterObject)
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) {
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());
}
}
}
}
/**
* 根据数据库方言,生成特定的分页sql
* @param sql
*
@param page
*
@return
*/
private
String generatePageSql(String
sql,Page
page){
if(page!=null
&& Tools.notEmpty(dialect)){
StringBuffer
pageSql =
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开始的
int
offset = (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
}
return
pageSql.toString();
}else{
return
sql;
}
}
/**
* 最先进入的方法
* @param arg0
*
@return
*/
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
(isEmpty(dialect)) {
try
{
throw new
PropertyException("dialect property is not found!");
} catch
(PropertyException
e) {
//
TODO Auto-generated catch block
e.printStackTrace();
}
}
pageSqlId
=
1cd44
p.getProperty("pageSqlId");
if
(isEmpty(pageSqlId)) {
try
{
throw new
PropertyException("pageSqlId property is not found!");
} catch
(PropertyException
e) {
//
TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* 检测字符串是否为空(null,"","null")
* @param s
*
@return 为空则返回true,不否则返回false
*/
public static boolean
isEmpty(String
s){
return
s==null
|| "".equals(s)
|| "null".equals(s);
}
}
具体说明都在注释中
1.3 补充说明
最好让这三个文件同包调用配置数据库方言和拦截字段在Mybatis-configuration.xml
配置文件中
具体如下:
<plugins>
<plugin
interceptor="main.java.com.jt.core.util.PagePlugin">
<property
name="dialect"
value="mysql"/>
<property
name="pageSqlId"
value=".*test$"/>
</plugin>
</plugins>
这个操作是注册拦截器
其中,dialect是数据库方言 现在支持mysql和oracle两种数据库的分页
pageSqlId是拦截的sql id
匹配Mapper接口中的方法名 和
Mapper.xml中的select id (使用正则匹配的方式 如例子中的贪婪匹配所有以test结尾的字段)。
最后需要注意除了分页以外的其他数据库独有的写法需要避免。
1.4 实现例子
ZhaoBiaoMapper数据层接口的方法://测试mybatis拦截器
ArrayList<ZhaoBiao>
zbpagetest(ZhaoBiao
zhaoBiao);
映射的Mapper.xml中的实现:
<select
id="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(ZhaoBiao
zhaoBiao);
实现类:
@Override
public ArrayList<ZhaoBiao>
listzb(ZhaoBiao
zhaoBiao) {
return
zhaoBiaoMapper.zbpagetest(zhaoBiao);
}
控制层:
@RequestMapping("/test")
@ResponseBody
public void test(){
Page
page =
new Page();
page.setPagesize(20);
ZhaoBiao
zhaoBiao =new
ZhaoBiao();
zhaoBiao.setPage(page);
ArrayList<ZhaoBiao>list
= zhaoBiaoService.listzb(zhaoBiao);
Integer
total =
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_field
varchar(100),# 主键 表格主键
必填 影响后面查询速度
in pagesize int
#一页显示数据的条数
)
begin
declare sTemp varchar(1000);
#初始化数据 需要的sql语句 下面两个作用相同
declare
sSql varchar(4000);
declare
sOrder varchar(1000);
if
asc_field =
1 then
# 排序是1的时候 反向排列
set
sOrder =
concat(' order by ',
order_field,
' desc ');# 设置排序语句
set
sTemp =
'<(select min';
# 逆序的时候查最小
else
set sOrder
= concat(' order by ',
order_field,
' asc ');# 正序的order语句
set
sTemp =
'>(select max';# 正序查最大
end if;
if
currpage =
1 then
# 第一页
if
sCondition <>
'' then
# 查询条件不为空的时候
set
sSql =
concat('select ',
columns,
' from ',
tablename,
' where ');# 拼接查询语句
set
sSql =
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);
set
sSql =
concat(sSql,
' where ',
sCondition,
' and ',
primary_field,
sTemp);
# select * from t_zb where 1=1 and zbid<(select min
set
sSql =
concat(sSql,
'(',
primary_field,
')',
' from (select ');# select * from t_zb where 1=1 and zbid<(select min(zbid) from (select
set
sSql =
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
set
sSql =
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
set
sSql =
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);
set
sSql =
concat(sSql,
' where ',
primary_field,
sTemp);
set
sSql =
concat(sSql,
'(',
primary_field,
')',
' from (select ');
set
sSql =
concat(sSql,
' ',
primary_field,
' from ',
tablename,
sOrder);
set
sSql =
concat(sSql,
' limit ', (currpage-1)*pagesize,
') as tabtemp)',
sOrder);
set
sSql =
concat(sSql,
' limit ?');
end if;
end if;
set
@iPageSize =
pagesize;
# 设置动态数据
set
@sQuery =
sSql;
# 查询语句
prepare
stmt from
@sQuery;
# 预查询
execute
stmt using
@iPageSize;#动态塞入参数 mysql5.1版本以前不支持
end;
$$
delimiter ;
解析出来:
需要提前在数据库命令符界面
复制代码并输入这段存储过程
使用Mybatis进行操作:
数据层接口:
ArrayList<ZhaoBiao>
cqgc(HashMap
map);
映射:
<select
id="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>
业务层:
Integer
ocunttest();//前面返回参数没有意义,仅仅测试
实现类:
@Override
public Integer
ocunttest() {
HashMap
map =
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);
if
sCondition <>
'' then
set sSql
= concat('select ',
columns,
' from ',
tablename);
set
sSql =
concat(sSql,
' where ',sCondition);
set
sSql =
concat(sSql,' ',order_field,'
limit ',(currpage-1)*pagesize,',',pagesize);
else
set sSql
= concat('select ',
columns,
' from ',
tablename);
set
sSql =
concat(sSql,' ',order_field,'
limit ',(currpage-1)*pagesize,',',pagesize);
end if;
set
@sQuery =
sSql;
# 查询语句
prepare
stmt from
@sQuery;
# 预查询
execute
stmt ;
end;
$$
delimiter ;
Mapper接口中的方法:
ArrayList<ZhaoBiao>
cqgcforone(HashMap
map);
映射:
<select
id="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>
业务层:
void
ccgc();
实现类:
@Override
public void ccgc() {
String
mc =
"b";
HashMap
map =
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);
ArrayList
list =
zhaoBiaoMapper.cqgcforone(map);
System.out.println(list.toArray());
}
测试结果:(控制层和上面的存储过程的类似)
最后总结 放上去的项目是一个没有被使用的项目作为演示
两种分页方式呢 个人认为 拦截器的应用可能会更加适合现在的行情 现在的很多思路都是做成拦截器 像现在很火的权限框架shiro 内部也需要根据业务去实现很多自定义的拦截器
而关于存储过程 个人认为可以将大数据的优化sql写成存储过程 这样也可以减少人力的投入 也实现了sql 的复用
相关文章推荐
- loner_li AJax 实现数据的 无刷新分页 实例(引用web服务文件和存储过程)
- 用存储过程实现分页显示
- 实现分页的通用存储过程(第二种)
- oracle实现存储过程的分页并用java代码调用存储过程
- 在MS SQLServer中使用存储过程实现通用分页
- 调用存储过程实现分页(一)
- Oracle之存储过程实现分页
- ASP.NET存储过程实现分页效果(三层架构)
- TOP n 实现的通用分页存储过程
- 通过存储过程实现分页
- 三层架构+存储过程实现分页
- 使用存储过程实现分页打印
- sql2005 存储过程实现分页
- 三大数据库下的存储过程实现通用分页
- Ibatis调用存储过程实现增删改以及分页查询
- 存储过程实现分页(不使用控件)
- 调用存储过程实现分页(二)
- 实现小数据量和海量数据的通用分页显示存储过程
- 使用系统存储过程实现的通用分页存储过程
- 实现千万级数据分页的存储过程