分页实现的三种方式java
三种分页的实现方式
(1)每次取查询结果的全部数据,而后根据页面显示指定的记录
(2)根据页面只取一页的数据,而后显示这一页,这里要构造sql语句
(3)取必定页数的数据,就是前两种的折中
实现分页的步骤:
1.建立一个用于封装分页相关属性及操做的类
2.从页面增长分页导航条的功能
3.实现分页查询功能,从页面请求->Servlet->DAO的实现mysql
这里还要注意的是这些数据是放在request仍是session中,这里一一讨论
1.通常不会放在session中,由于会占用大量内存,因此要放在request里面。
优势:实现比较简单,查询速度比较快。
缺点:占用内存多一些,网络传输数据多。
对于数据量比较少的查询这种方法比较合适。这里有人把数据放在session中,这样换页的时候就不用从新查询,可是这样是极其很差的,强烈建议不要这样使用。
2.确定不会放在session中,由于放在session中没有意义。
优势:占用内存少。
缺点:比较麻烦,必须先得到查询结果的总数,由于要知道有多少纪录才知道有多少页。另外要构造分页查询语句,对于不一样的数据库是不同的。 sql
一.借助数组进行分页数据库
原理:进行数据库查询操做时,获取到数据库中全部知足条件的记录,保存在应用的临时数组中,再经过List的subList方法,获取到知足条件的全部记录。apache
实现:数组
首先在dao层,建立StudentMapper接口,用于对数据库的操做。在接口中定义经过数组分页的查询方法,以下所示:网络
Listsession
建立StudentMapper.xml文件,编写查询的sql语句:app
能够看出再编写sql语句的时候,咱们并无做任何分页的相关操做。这里是查询到全部的学生信息。性能
接下来在service层获取数据而且进行分页实现:
定义IStuService接口,而且定义分页方法:
经过接收currPage参数表示显示第几页的数据,pageSize表示每页显示的数据条数。
建立IStuService接口实现类StuServiceIml对方法进行实现,对获取到的数组经过currPage和pageSize进行分页:
经过subList方法,获取到两个索引间的全部数据。
最后在controller中建立测试方法:
经过用户传入的currPage和pageSize获取指定数据。
二.借助Sql语句进行分页
在了解到经过数组分页的缺陷后,咱们发现不能每次都对数据库中的全部数据都检索。而后在程序中对获取到的大量数据进行二次操做,这样对空间和性能都是极大的损耗。因此咱们但愿能直接在数据库语言中只检索符合条件的记录,不须要在经过程序对其做处理。这时,Sql语句分页技术横空出世。
实现:经过sql语句实现分页也是很是简单的,只是须要改变咱们查询的语句就能实现了,即在sql语句后面添加limit分页语句。
List
接下来仍是在IStuService接口中定义方法,而且在StuServiceIml中对sql分页实现。
ql分页语句以下:select * from table limit index, pageSize;
因此在service中计算出currIndex:要开始查询的第一条记录的索引。
三.拦截器分页
上面提到的数组分页和sql语句分页都不是咱们今天讲解的重点,今天须要实现的是利用拦截器达到分页的效果。自定义拦截器实现了拦截全部以ByPage结尾的查询语句,而且利用获取到的分页相关参数统一在sql语句后面加上limit分页的相关语句,一劳永逸。再也不须要在每一个语句中单独去配置分页相关的参数了。。
首先咱们看一下拦截器的具体实现,在这里咱们须要拦截全部以ByPage结尾的全部查询语句,所以要使用该拦截器实现分页功能,那么再定义名称的时候须要知足它拦截的规则(以ByPage结尾),
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import java.sql.Connection;
import java.util.Map;
import java.util.Properties;
/**
/**
//每页显示的条目数
private int pageSize;
//当前现实的页数
private int currPage;
//若是项目中分页的pageSize是统一的,也能够在这里统一配置和获取,这样就不用每次请求都传递pageSize参数了。参数是在配置拦截器时配置的。
String limit1 = properties.getProperty("limit", "10");
this.pageSize = Integer.valueOf(limit1);
this.dbType = properties.getProperty("dbType", "mysql");
}
}
上面便是拦截器功能的实现,在intercept方法中获取到select标签和sql语句的相关信息,拦截全部以ByPage结尾的select查询,而且统一在查询语句后面添加limit分页的相关语句,统一实现分页功能。
重点详解:
StatementHandler是一个接口,而咱们在代码中经过StatementHandler statementHandler = (StatementHandler) invocation.getTarget();获取到的是StatementHandler默认的实现类RoutingStatementHandler。而RoutingStatementHandler只是一个中间代理,他不会提供具体的方法。那你可能会纳闷了,拦截器中基本上是依赖statementHandler获取各类对象和属性的,没有具体属性和方法怎么行??接着看下面代码:
private final StatementHandler delegate;
原来它是经过不一样的MappedStatement建立不一样的StatementHandler实现类对象处理不一样的状况。这里的到的StatementHandler实现类才是真正服务的。看到这里,你可能就会明白MappedStatement mappedStatement = (MappedStatement) MetaObjectHandler.getValue("delegate.mappedStatement");中delegate的来源了吧。至于为何要这么去获取,后面咱们会说道。
拿到statementHandler后,咱们会经过MetaObject MetaObjectHandler = SystemMetaObject.forObject(statementHandler);去获取它的包装对象,经过包装对象去获取各类服务。
接下来讲说:MappedStatement mappedStatement = (MappedStatement) MetaObjectHandler.getValue("delegate.mappedStatement");
上面提到为何要这么去获取MappedStatement对象??在RoutingStatementHandler中delegate是私有的(private final StatementHandler delegate;),有没有共有的方法去获取。因此这里只有经过反射来获取啦。
MappedStatement是保存了xxMapper.xml中一个sql语句节点的全部信息的包装类,能够经过它获取到节点中的全部信息。在示例中咱们拿到了id值,也就是方法的名称,经过名称区拦截全部须要分页的请求。
经过StatementHandler的包装类,不光能拿到MappedStatement,还能够拿到下面的数据:
上面的全部数据均可以经过反射拿到。
几个重要的参数:
Configuration:全部配置的相关信息。
ResultSetHandler:用于拦截执行结果的组装。
ParameterHandler:拦截执行Sql的参数的组装。
Executor:执行Sql的全过程,包括组装参数、组装结果和执行Sql的过程。
BoundSql:执行的Sql的相关信息。
接下来咱们经过以下代码拿到请求时的map对象(反射)。
如上所示,还能在里面配置一些属性,在拦截器的setProperties方法中能够获取配置好的属性值。如项目分页的pageSize参数的值固定,咱们就能够配置在这里了,之后就不须要每次传入pageSize了,读取方式以下:
到这里,有关拦截器的相关知识就讲解的差很少了,接下来就须要测试,是否咱们这样写真的有效??
首先仍是添加dao层的方法和xml文件的sql语句配置,注意项目中拦截的是以ByPage结尾的请求,因此在这里,咱们的方法名称也以此结尾:
方法
实现:
这里咱们虽然传入了currPage和pageSize两个参数,可是在sql的xml文件中并无使用,直接在拦截器中获取到统一使用。
最后编写controller的测试代码: