Mybatis 分页详解前言 在学习mybatis等持久层框架的时候,会经常对数据进行增删改查操作,使用最多的是对数据库进行查询操作,如果查询大量数据的时候,我们往往使用分页进行查询,也就是每次处理小部分数据,这样对数据库压力就在可控范围内。 分页的几种方式 1. 内存分页 内存分页的原理比较sb,就是一次性查询数据库中所有满足条件的记录,将这些数据临时保存在集合中,再通过List的subList方法,获取到满足条件的记录,由于太sb,直接忽略该种方式的分页。 2. 物理分页 在了解到通过内存分页的缺陷后,我们发现不能每次都对数据库中的所有数据都检索。然后在程序中对获取到的大量数据进行二次操作,这样对空间和性能都是极大的损耗。所以我们希望能直接在数据库语言中只检索符合条件的记录,不需要在通过程序对其作处理。这时,物理分页技术横空出世。 物理分页是借助sql语句进行分页,比如mysql是通过limit关键字,oracle是通过rownum等;其中mysql的分页语法如下: select * from table limit 0,30 MyBatis 分页 1.借助sql进行分页 通过sql语句进行分页的实现很简单,我们先在StudentMapper接口中添加sql语句的查询方法,如下: List queryStudentsBySql(@Param("offset") int offset, @Param("limit") int limit); StudentMapper.xml 配置如下: select * from student limit #{offset} , #{limit} 客户端使用的时候如下: public List queryStudentsBySql(int offset, int pageSize) {
return studentMapper.queryStudentsBySql(offset,pageSize); } sql分页语句如下:select * from table limit index, pageSize; 缺点:虽然这里实现了按需查找,每次检索得到的是指定的数据。但是每次在分页的时候都需要去编写limit语句,很冗余, 其次另外如果想知道总条数,还需要另外写sql去统计查询。而且不方便统一管理,维护性较差。所以我们希望能够有一种更方便的分页实现。 2. 拦截器分页 拦截器的一个作用就是我们可以拦截某些方法的调用,我们可以选择在这些被拦截的方法执行前后加上某些逻辑,也可以在执行这些被拦截的方法时执行自己的逻辑而不再执行被拦截的方法。Mybatis拦截器设计的一个初衷就是为了供用户在某些时候可以实现自己的逻辑而不必去动Mybatis固有的逻辑。打个比方,对于Executor,Mybatis中有几种实现:BatchExecutor、ReuseExecutor、SimpleExecutor和CachingExecutor。这个时候如果你觉得这几种实现对于Executor接口的query方法都不能满足你的要求,那怎么办呢?是要去改源码吗?当然不。我们可以建立一个Mybatis拦截器用于拦截Executor接口的query方法,在拦截之后实现自己的query方法逻辑,之后可以选择是否继续执行原来的query方法。 Interceptor接口 对于拦截器Mybatis为我们提供了一个Interceptor接口,通过实现该接口就可以定义我们自己的拦截器。我们先来看一下这个接口的定义: package org.apache.ibatis.plugin; import java.util.Properties; public interface Interceptor {
Object intercept(Invocation invocation) throws Throwable; Object plugin(Object target); void setProperties(Properties properties); } 我们可以看到在该接口中一共定义有三个方法,intercept、plugin和setProperties。plugin方法是拦截器用于封装目标对象的,通过该方法我们可以返回目标对象本身,也可以返回一个它的代理。当返回的是代理的时候我们可以对其中的方法进行拦截来调用intercept方法,当然也可以调用其他方法,这点将在后文讲解。setProperties方法是用于在Mybatis配置文件中指定一些属性的。 定义自己的Interceptor最重要的是要实现plugin方法和intercept方法,在plugin方法中我们可以决定是否要进行拦截进而决定要返回一个什么样的目标对象。而intercept方法就是要进行拦截的时候要执行的方法。 对于plugin方法而言,其实Mybatis已经为我们提供了一个实现。Mybatis中有一个叫做Plugin的类,里面有一个静态方法wrap(Object target,Interceptor interceptor),通过该方法可以决定要返回的对象是目标对象还是对应的代理。这里我们先来看一下Plugin的源码: package org.apache.ibatis.plugin; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.apache.ibatis.reflection.ExceptionUtil; public class Plugin implements InvocationHandler {
private Object target; private Interceptor interceptor; private Map, Set> signatureMap; private Plugin(Object target, Interceptor interceptor, Map, Set> signatureMap) {
|