分页插件PageHelper工作原理
1. 原理概述
PageHelper是MyBatis的一个插件,内部实现了一个PageInterceptor拦截器。Mybatis会加载这个拦截器到拦截器链中。在我们使用过程中先使用PageHelper.startPage这样的语句在当前线程上下文中设置一个ThreadLocal变量,再利用PageInterceptor这个分页拦截器拦截,从ThreadLocal中拿到分页的信息,如果有分页信息拼装分页SQL(limit语句等)进行分页查询,最后再把ThreadLocal中的东西清除掉。
部分源码可知设置了一个ThreadLocal变量:
2. 使用注意事项
PageHelper使用了ThreadLocal保存分页参数,分页参数和线程是绑定的。因此我们需要保证PageHelper 的startPage调用后紧跟 MyBatis 查询方法,这就是安全的。因为 PageHelper 在 finally 代码段中自动清除了 ThreadLocal 存储的对象。
如果代码在进入Executor前发生异常,就会导致线程不可用,这属于人为Bug(例如接口方法和XML中的不匹配,导致找不到MapppedStatement时)。这种情况由于线程不可用,也不会导致 ThreadLocal参数被错误使用。
但是如果写出以下代码,就是不安全的用法:
1 | PageHelper.startPage(1, 10); |
这种情况下由于param1存在null的情况,就会导致PageHelper产生了一个分页参数,但是没有被消费,也没有被清理。这个参数就会一直保存在ThreadLocal中。可能导致其它不该分页的方法去消费了这个参数,莫名其妙的做了分页。
此外如果考虑到发生异常,可以加一个finally块,手动清理参数。