pageHelper没有正确分页,sql拼接多加limit等参数。

背景:

日常敲代码,发现用了pageHelper真的方便,尤其是使用了pageInfo这个类,不用自己写工具类了,直接将所有的页码信息封装到PageInfo里,但是,使用过程中发生了sql语法错误,查看之后发现sql语句又多加了limit或者在不应该排序的地方加了一个排序的规则。而且项目有的时候正常有的时候错误。

  1. 不分页,查出多少条数据给出多少条:

    image-20200729165321936

    没有分页标志。

  2. 多次刷新页面

image-20200729165413035

出现这个,明明没加limit,这个mapper也没有分页。

  1. 多次刷新后查出来的数据也不正确了。库里明明有12条数据,结果查出来5条。

image-20200729165543921

image-20200729165609883

有时候正确有时候错误。

解决方案

查看自己的写语句,既然不分页,先考虑是不是代码没有写对。

@GetMapping("/types/{id}")
public String types(Model model, @RequestParam(value = "page",required = false) Integer pageNum, @PathVariable Long id) {
    //找出所有的type
    List<TypeIndexDto> types = typeService.listType2Index();
    if (pageNum==null){
        pageNum=1;
    }
    if (id == -1) {
        id = types.get(0).getId();
    }
    //根据typeId查询所属博客并罗列出来
    List<BlogIndexDto> blogIndexDtos = blogService.selectBlogByTypeId(id);
    PageHelper.startPage(pageNum,5);
    PageInfo<BlogIndexDto> pageInfo = new PageInfo<>(blogIndexDtos);
    model.addAttribute("types", types);
    model.addAttribute("page", pageInfo);
    model.addAttribute("activeType", id);
    return "types";
}

乍一看,其实没有问题,但是读到官网的这一条:

image-20200729165826075

顺序写错了。。。纠错老长时间,修改下顺序就行了。

当然,按照官网说的,使用PageHelper方法有可能产生线程安全问题,其实这就是因为pageHelper没有跟在mybatis查询方法之后导致的线程安全。具体可以查看官网。

官网的解释

PageHelper 方法使用了静态的 ThreadLocal 参数,分页参数和线程是绑定的。

只要你可以保证在 PageHelper 方法调用后紧跟 MyBatis 查询方法,这就是安全的。因为 PageHelperfinally 代码段中自动清除了 ThreadLocal 存储的对象。

如果代码在进入 Executor 前发生异常,就会导致线程不可用,这属于人为的 Bug(例如接口方法和 XML 中的不匹配,导致找不到 MappedStatement 时), 这种情况由于线程不可用,也不会导致 ThreadLocal 参数被错误的使用。

但是如果你写出下面这样的代码,就是不安全的用法:

PageHelper.startPage(1, 10);
List<User> list;
if(param1 != null){
    list = userMapper.selectIf(param1);
} else {
    list = new ArrayList<User>();
}

这种情况下由于 param1 存在 null 的情况,就会导致 PageHelper 生产了一个分页参数,但是没有被消费,这个参数就会一直保留在这个线程上。当这个线程再次被使用时,就可能导致不该分页的方法去消费这个分页参数,这就产生了莫名其妙的分页。

上面这个代码,应该写成下面这个样子:

List<User> list;
if(param1 != null){
    PageHelper.startPage(1, 10);
    list = userMapper.selectIf(param1);
} else {
    list = new ArrayList<User>();
}

这种写法就能保证安全。

如果你对此不放心,你可以手动清理 ThreadLocal 存储的分页参数,可以像下面这样使用:

List<User> list;
if(param1 != null){
    PageHelper.startPage(1, 10);
    try{
        list = userMapper.selectAll();
    } finally {
        PageHelper.clearPage();
    }
} else {
    list = new ArrayList<User>();
}

这么写很不好看,而且没有必要。

总结

在改错的过程中,一度怀疑是pageHelper出了问题,想重写分页工具类,经过排错后发现,根本不用,只要自己按照官网的来就可以避免不安全的调用pageHelper的方法。

 posted on 2020-07-29 17:03  ben跑的换行符  阅读(2191)  评论(1编辑  收藏  举报