PageHelper 插件,无故给 SQL 增加 Limit 问题

在使用MyBatis的PageHelper插件进行分页查询时,若在PageHelper.startPage和分页查询语句间有其他逻辑,可能导致后续SQL被意外加上Limit。解决办法是确保startPage与查询语句紧邻,或在适当位置调用clearPage以清除分页参数。避免因线程复用导致的潜在问题。
摘要由CSDN通过智能技术生成

33a682cff7807983ff227790293c3891.png

在项目中,使用了 MyBatis 的 PageHelper 插件,发现了一个奇怪的问题,经常会给SQL无缘无故的增加Limit语句,经过调查,发现原因是没有安全的使用PageHelper插件,先来看一个例子:

1PageHelper.startPage(pageable.getPageNumber(), pageable.getPageSize());
 2PageInfolist = null;
 3if (condition.getCustomerIdListForUser() != null && condition.getCustomerIdListForUser().size() > 0) {
 4    list = new PageInfo<>(orderMapper.findOrderList(condition)); //分页查询语句
 5} else {
 6    list = new PageInfo<>(new ArrayList());
 7    list.setPageNum(0);
 8    list.setPageSize(1);
 9    list.setTotal(0);
10}

       在例子中,PageHelper.startPage就属于明显的不安全调用,因为PageHelper的原理是,在PageHelper.startPage调用时,会给全局对象LOCAL_PAGE设值,然后通过拦截器拦截每个SQL语句,如果LOCAL_PAGE有值,则给该SQL增加Limit,并调用clearPage方法清除LOCAL_PAGE的值;

       但是上面的代码,其分页查询语句有可能因为if的条件的不满足没有执行,所以在程序执行结束时,PageHelper.startPage已经执行,LOCAL_PAGE的值已经设置

      当线程池再次分配该线程执行其他程序时,可能会在该程序的第一个SQL上增加了Limit语句。

       解决该问题的方法是,要绝对保证PageHelper.startPage和分页查询语句之间不要有任何其他语句,或者在程序结束时增加PageHelper.clearPage();的调用,例:

1PageInfolist = null;
 2if (condition.getCustomerIdListForUser() != null && condition.getCustomerIdListForUser().size() > 0) {
 3      PageHelper.startPage(pageable.getPageNumber(), pageable.getPageSize());
 4     list = new PageInfo<>(orderMapper.findOrderList(condition));//分页查询语句
 5} else {
 6    list = new PageInfo<>(new ArrayList());
 7    list.setPageNum(0);
 8    list.setPageSize(1);
 9    list.setTotal(0);
10}

1PageHelper.startPage(pageable.getPageNumber(), pageable.getPageSize());
 2PageInfolist = null;
 3if (condition.getCustomerIdListForUser() != null && condition.getCustomerIdListForUser().size() > 0) {
 4     list = new PageInfo<>(orderMapper.findOrderList(condition));
 5} else {
 6     list = new PageInfo<>(new ArrayList());
 7     list.setPageNum(0);
 8     list.setPageSize(1);
 9     list.setTotal(0);
10}
11PageHelper.clearPage();

另外也可以这样

1PageHelper.startPage(pageable.getPageNumber(), pageable.getPageSize());
 2PageInfolist = null;
 3if (condition.getCustomerIdListForUser() != null && condition.getCustomerIdListForUser().size() > 0) {
 4    try{
 5        list = new PageInfo<>(orderMapper.findOrderList(condition));
 6    }finally{
 7        PageHelper.clearPage();
 8    }
 9} else {
10     list = new PageInfo<>(new ArrayList());
11     list.setPageNum(0);
12     list.setPageSize(1);
13     list.setTotal(0);
14}

但是这样写有点冗余,而且没有必要。

官网的解释 :

PageHelper 方法使用了静态的 ThreadLocal 参数,分页参数和线程是绑定的。只要可以保证在 PageHelper 方法调用后紧跟 MyBatis 查询方法,这就是安全的。因为 PageHelper 在 finally 代码段中自动清除了 ThreadLocal 存储的对象。如果代码在进入 Executor 前发生异常,就会导致线程不可用,这属于人为的 Bug(例如,接口方法和 XML 中的不匹配,导致找不到 MappedStatement 时), 这种情况由于线程不可用,也不会导致 ThreadLocal 参数被错误的使用。

eb5773d4ad0e379b1d732e524da5cd46.png

喜欢,在看

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值