• 分页实现的三种方式


    分页实现的三种方式

    三种分页的实现方式
    (1)每次取查询结果的所有数据,然后根据页面显示指定的记录
    (2)根据页面只取一页的数据,然后显示这一页,这里要构造sql语句
    (3)取一定页数的数据,就是前两种的折中
    实现分页的步骤:
    1.创建一个用于封装分页相关属性及操作的类
    2.从页面增加分页导航条的功能
    3.实现分页查询功能,从页面请求->Servlet->DAO的实现

    这里还要注意的是这些数据是放在request还是session中,这里一一讨论

    1.一般不会放在session中,因为会占用大量内存,所以要放在request里面。
    优点:实现比较简单,查询速度比较快。
    缺点:占用内存多一些,网络传输数据多。
    对于数据量比较少的查询这种方法比较合适。这里有人把数据放在session中,这样换页的时候就不用重新查询,但是这样是极其不好的,强烈建议不要这样使用。

    2.肯定不会放在session中,因为放在session中没有意义。
    优点:占用内存少。
    缺点:比较麻烦,必须先获得查询结果的总数,因为要知道有多少纪录才知道有多少页。另外要构造分页查询语句,对于不同的数据库是不一样的。

    一.借助数组进行分页

    • 原理:进行数据库查询操作时,获取到数据库中所有满足条件的记录,保存在应用的临时数组中,再通过List的subList方法,获取到满足条件的所有记录。

    • 实现:

    首先在dao层,创建StudentMapper接口,用于对数据库的操作。在接口中定义通过数组分页的查询方法,如下所示:

    List

    创建StudentMapper.xml文件,编写查询的sql语句:

    可以看出再编写sql语句的时候,我们并没有作任何分页的相关操作。这里是查询到所有的学生信息。

    接下来在service层获取数据并且进行分页实现:

    定义IStuService接口,并且定义分页方法:

    通过接收currPage参数表示显示第几页的数据,pageSize表示每页显示的数据条数。

    创建IStuService接口实现类StuServiceIml对方法进行实现,对获取到的数组通过currPage和pageSize进行分页:

    通过subList方法,获取到两个索引间的所有数据。

    最后在controller中创建测试方法:

    通过用户传入的currPage和pageSize获取指定数据。

    二.借助Sql语句进行分页

    在了解到通过数组分页的缺陷后,我们发现不能每次都对数据库中的所有数据都检索。然后在程序中对获取到的大量数据进行二次操作,这样对空间和性能都是极大的损耗。所以我们希望能直接在数据库语言中只检索符合条件的记录,不需要在通过程序对其作处理。这时,Sql语句分页技术横空出世。

    实现:通过sql语句实现分页也是非常简单的,只是需要改变我们查询的语句就能实现了,即在sql语句后面添加limit分页语句。

    • 首先还是在StudentMapper接口中添加sql语句查询的方法,如下:

    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;

    /**

    /**

    • @Intercepts 说明是一个拦截器
    • @Signature 拦截器的签名
    • type 拦截的类型 四大对象之一( Executor,ResultSetHandler,ParameterHandler,StatementHandler)
    • method 拦截的方法
    • args 参数
      */
      @Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
      public class MyPageInterceptor implements Interceptor {

    //每页显示的条目数
    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的测试代码:

  • 相关阅读:
    中国首届React开发者大会 8月18日 广州举行
    事件循环:Flutter 中代码是如何执行和运行的
    大前端趋势所向:这么多跨端技术,为什么选择 Flutter?
    通往大前端的一把关键钥匙 Flutter
    如何选一部好的手机?性价比高的智能手机推荐,2020智能手机排行榜!
    智能手机边充电边玩对电池有什么损害吗?
    你的智能手机究竟能用多久?
    新型添加技术
    智能手机
    姐姐不愧是姐姐,快看《乘风破浪的姐姐》
  • 原文地址:https://www.cnblogs.com/3020815dzq/p/9020182.html
Copyright © 2020-2023  润新知