这个问题的起因是前端查询对应表数据的时候,发现当数据库中没有对应数据时会报错:java.util.ArrayList cannot be cast to com.github.pagehelper.Page.
一. 结论先行
主要原因:代码在进入Executor前发生异常,就会导致线程不可用,接口方法和XML中的不匹配,导致找不到MappedStatement.这种情况由于线程不可用,所以不会导致ThreadLocal参数被错误的使用.
解决:注释部分是我之前的代码,用的是等值查询.由于我想把前端页面的精确查询改成模糊查询,所以把查询调用的eq方法改为like方法.但是没改xml文件导致了报错.修改后就没有这种问题了.
总结::代码本身没有问题,是我的查询方法跟我的xml不匹配导致的.
二.什么时候会导致不安全的分页?
PageHelper方法使用了静态的ThreadLocal参数,分页参数和线程是绑定的.
只要你可以保证在PageHelper方法调用后紧跟MyBatis查询方法,这就是安全的.因为PageHelper在finally代码段中自动清除来ThreadLocal存储的对象.
如果代码在进入Executor前发生异常,就会导致线程不可用,这属于人为的Bug(例如接口方法和XML中的不匹配,导致找不到MappedStatement时),这种情况由于线程不可用,也不会导致ThreadLocal参数被错误的使用.
但是如果你写出下面这种代码,就是不安全的用法:
PageHelper.startPage(1, 10);
List<Country> list;
if(param1 != null){
list = countryMapper.selectIf(param1);
} else {
list = new ArrayList<Country>();
}
这种情况下由于param1存在null的情况,就会导致PageHelper生产了一个分页参数,但是没有被消费,这个参数就会一直保留在这个线程上.当这个线程再次被使用时,就可能导致不该分页的方法去消费这个分页参数,这就产生了莫名其妙的分页.
上述代码,应该写成下面这个样子:
List<Country> list;
if(param1 != null){
PageHelper.startPage(1, 10);
list = countryMapper.selectIf(param1);
} else {
list = new ArrayList<Country>();
}
这样写能保证安全.
如果你对此不放心,你可以手动清理ThreadLocal存储的分页参数,可以像下面这种:
List<Country> list;
if(param1 != null){
PageHelper.startPage(1, 10);
try{
list = countryMapper.selectAll();
} finally {
PageHelper.clearPage();
}
} else {
list = new ArrayList<Country>();
}
不过这样写不好看,而且也没必要.