pageHelper没有正确分页,sql拼接多加limit等参数。
背景:
日常敲代码,发现用了pageHelper真的方便,尤其是使用了pageInfo这个类,不用自己写工具类了,直接将所有的页码信息封装到PageInfo里,但是,使用过程中发生了sql语法错误,查看之后发现sql语句又多加了limit或者在不应该排序的地方加了一个排序的规则。而且项目有的时候正常有的时候错误。
-
不分页,查出多少条数据给出多少条:
没有分页标志。
-
多次刷新页面
出现这个,明明没加limit,这个mapper也没有分页。
- 多次刷新后查出来的数据也不正确了。库里明明有12条数据,结果查出来5条。
有时候正确有时候错误。
解决方案
查看自己的写语句,既然不分页,先考虑是不是代码没有写对。
@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";
}
乍一看,其实没有问题,但是读到官网的这一条:
顺序写错了。。。纠错老长时间,修改下顺序就行了。
当然,按照官网说的,使用PageHelper方法有可能产生线程安全问题,其实这就是因为pageHelper没有跟在mybatis查询方法之后导致的线程安全。具体可以查看官网。
官网的解释
PageHelper
方法使用了静态的 ThreadLocal
参数,分页参数和线程是绑定的。
只要你可以保证在 PageHelper
方法调用后紧跟 MyBatis 查询方法,这就是安全的。因为 PageHelper
在 finally
代码段中自动清除了 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的方法。