乐趣区

关于mybatis:mybatis如何集成分页插件其实很简单啦

关注“Java 后端技术全栈”

回复“面试”获取全套面试材料

本文次要内容:

大多数框架都反对插件,用户可通过编写插件来自行扩大性能,Mybatis 也不例外。

在 Mybatis 中最闻名的就是 PageHelper 分页插件,上面咱们先来应用一下这个分页插件。

如何集成分页插件

Spring-Boot+Mybatis+PageHelper。

引入 pom 依赖

<dependency>
   <groupId>com.github.pagehelper</groupId>
   <artifactId>pagehelper-spring-boot-starter</artifactId>
   <version>1.2.3</version>
</dependency>

配置分页插件配置项

pagehelper:
  helperDialect: mysql
  reasonable: true
  supportMethodsArguments: true
  params: count=countSql

service 接口代码中

PageInfo selectUsersByName(int pageIndex, int pageSize);

service 实现类代码中

@Override
public PageInfo selectUsersByName(int pageIndex, int pageSize) {PageHelper.startPage(pageIndex, pageSize);
    List<User> users = userMapper.selectUsersByName(null);
    return new PageInfo(users);
}

Mapper 代码代码

<select id="selectUsersByName" resultMap="User">
    select * from m_user
    <where>
        <if test="userName != null and userName !=''">
            `name` = #{userName}
        </if>
    </where>
</select>
List<User> selectUsersByName(@Param("userName") String userName);

controller 中代码

@GetMapping("/user/name")
public PageInfo selectUsersByName(int pageIndex, int pageSize) {return userService.selectUsersByName(pageIndex, pageSize);
}

而后咱们拜访

http://localhost:9002/user/name?pageIndex=1&pageSize=10

输入后果:

输入重要项阐明:

  • pageNum:以后页码。
  • pageSize:每页数。
  • list:就是咱们返回的业务数据。
  • total:总数据。
  • hasNextPage:是否存在下一页。

咱们在看看输入 SQL:

发现其实执行了两条 SQL:count 和 limit。

猜想分页插件实现

1. 这个分页插件无非就是在咱们的查问条件上拼接了个 limit 和做了一个 count 查问。

2. 咱们这里应用的是 Mysql 作为数据库,如果是 Oracle 的话那就不是 limit 了,所以这里有多重数据库对应的计划。

3. 在没有此插件的后面拦挡并做了 sql 和相干解决。

依据官网疾速入门插件

上面是来自官网的一段话:

MyBatis 容许你在映射语句执行过程中的某一点进行拦挡调用。默认状况下,MyBatis 容许应用插件来拦挡的办法调用包含:

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters)
  • ResultSetHandler (handleResultSets, handleOutputParameters)
  • StatementHandler (prepare, parameterize, batch, update, query)

这些类中办法的细节能够通过查看每个办法的签名来发现,或者间接查看 MyBatis 发行包中的源代码。如果你想做的不仅仅是监控办法的调用,那么你最好相当理解要重写的办法的行为。因为在试图批改或重写已有办法的行为时,很可能会毁坏 MyBatis 的外围模块。这些都是更底层的类和办法,所以应用插件的时候要特地当心。

通过 MyBatis 提供的弱小机制,应用插件是非常简单的,只需实现 Interceptor 接口,并指定想要拦挡的办法签名即可。

那咱们就尝试着依照官网来写一个插件。

自定义插件

@Intercepts({@Signature(
        type= Executor.class,
        method = "update",
        args = {MappedStatement.class,Object.class})})
public class TianPlugin implements Interceptor {private Properties properties = new Properties();
    @Override
    public Object intercept(Invocation invocation) throws Throwable {System.out.println("老田写的一个 Mybatis 插件 --start");
        Object returnObject = invocation.proceed();
        System.out.println("老田写的一个 Mybatis 插件 ---end");
        return returnObject;
    }
}

而后把插件类注入到容器中。

这里的自定义齐全是官网给出的案例。从自定义的插件类中看到有个 update,咱们猜想必定是须要执行 update 才会被拦挡到。

拜访后面的代码:http://localhost:9002/updateUser

胜利了。

这是大家必定会联想到咱们刚刚开始学动静代理的时候,不就是在要调用的办法的后面和前面做点小东东吗?

Mybatis 的插件的确就是这样的。

咱们来剖析一下官网的那段话和咱们自定义的插件。

剖析

首先,咱们自定义的插件必须是针对上面这四个类以及办法。

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters)
  • ResultSetHandler (handleResultSets, handleOutputParameters)
  • StatementHandler (prepare, parameterize, batch, update, query)

其次,咱们必须实现 Mybatis 的 Interceptor。

Interceptor 中三个办法的作用:

  • intercept():执行拦挡内容的中央,比方:在调用某类办法前后做一些本人的解决,简略就是打印日志。
  • plugin():决定是否触发 intercept() 办法。
  • setProperties():给自定义的拦截器传递咱们配置的属性参数(这个能够临时不论他,前面咱们写一个绝对残缺点的插件,你就明确是干啥的了)。
plugin 办法
default Object plugin(Object target) {return Plugin.wrap(target, this);
  }

默认实现办法,外面调用了 Plugin.wrap() 办法。

public class Plugin implements InvocationHandler {
  private Object target;
  private Interceptor interceptor;
  private Map<Class<?>, Set<Method>> signatureMap;
  private Plugin(Object target, Interceptor interceptor, Map<Class<?>, Set<Method>> signatureMap) {
    this.target = target;
    this.interceptor = interceptor;
    this.signatureMap = signatureMap;
  }
  public static Object wrap(Object target, Interceptor interceptor) {Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
    Class<?> type = target.getClass();
    Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
    if (interfaces.length > 0) {
      // 创立 JDK 动静代理对象
      return Proxy.newProxyInstance(type.getClassLoader(),
          interfaces,
          new Plugin(target, interceptor, signatureMap));
    }
    return target;
  }
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {Set<Method> methods = signatureMap.get(method.getDeclaringClass());
      // 判断是否是须要拦挡的办法 (很重要)
      if (methods != null && methods.contains(method)) {// 回调 intercept() 办法
        return interceptor.intercept(new Invocation(target, method, args));
      }
      return method.invoke(target, args);
    } catch (Exception e) {throw ExceptionUtil.unwrapThrowable(e);
    }
  }
//... 省略其余不相干代码
}

这不就是一个 JDK 动静代理吗?

Map<Class<?>, Set> signatureMap:缓存需拦挡对象的反射后果,防止屡次反射,即 target 的反射后果。

所以,咱们不要动不动就说反射性能很差,那是因为你没有像 Mybatis 一样去缓存一个对象的反射后果。

判断是否是须要拦挡的办法,这句正文很重要,一旦疏忽了,都不晓得 Mybatis 是怎么判断是否执行拦挡内容的,要记住。

Plugin.wrap(target, this) 是干什么的?

应用 JDK 的动静代理,给 target 对象创立一个 delegate 代理对象,以此来实现办法拦挡和加强性能,它会回调 intercept() 办法。

为什么要写注解?注解都是什么含意?

在咱们自定义的插件上有一堆注解,别胆怯。

Mybatis 规定插件必须编写 Annotation 注解,是必须,而不是可选。

@Intercepts({@Signature( type= Executor.class, method = "update",
                        args = {MappedStatement.class,Object.class})}
           )
public class TianPlugin implements Interceptor {

@Intercepts 注解:装载一个 @Signature 列表,一个 @Signature 其实就是一个须要拦挡的办法封装。那么,一个拦截器要拦挡多个办法,天然就是一个 @Signature 列表。

type= Executor.class, method = "update",args = {MappedStatement.class,Object.class}

解释:要拦挡 Executor 接口内的 query() 办法,参数类型为 args 列表。

那如果想拦挡多个办法呢?

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Intercepts {Signature[] value();}

这就简略了吧,咱们在 @Intercepts 注解中能够寄存多个 @Signature 注解。

比如说后面分页插件中就是拦挡多个办法的。

为什么拦挡两个都是 query 办法呢?因为在 Executor 中有两个 query 办法。

总结下:

Mybatis 规定必须应用 @Intercepts 注解。

@Intercepts 注解内能够增加多个类多个办法,留神办法名和参数类型个数肯定要对应起来。

举荐浏览

《图解数据结构》.pdf

面试官:你晓得对象的克隆原理吗?

《亿级流量网站架构核心技术》.pdf

退出移动版