问题说明
业务报错, 内容是SQL语法错误, 类似这样的, select name from table limit 1 LIMIT 10
, 在正常的SQL后面多加了一截 LIMIT 10
通过分析发现, 是因为PageHelper使用不正确导致了这个问题, 详细原因如下
有一段业务代码如下, 在第二行转换Date时因为requestNo字段为null报错, 导致执行了startPage却没有执行SQL, 从而影响了后续SQL的执行, 为什么会影响到后续SQL的执行呢?
PageHelper.startPage(pageNo, pageSize);
Date createdAt = DateTimeKit.parseFromCompactDateTime(request.getRequestNo().subString(0, 14));
List<XxxDO> list = tableMapper.selectByCreatedAt(createdAt);
我们使用的是Dubbo体系, 每一个请求从Dubbo线程池中获取一个线程执行业务, 执行结束后, 线程不会被销毁, 而是归还回Dubbo线程池.
而PageHelper通过使用ThreadLocal保存某个线程下的分页信息, 正常情况下, 第一行保存, 第三行使用并清除. 第二行异常时, 第一行保存, 没有执行第三行, 所以就没有从ThreadLocal中清理掉该线程的信息. 该线程就被归还回了Dubbo线程池
当另一个请求重新使用该Dubbo线程的时候, 执行第一条SQL时, PageHelper检查到ThreadLocal中有该线程的分页信息, 这时就会改写该线程, 添加了一些不可预料的内容, 导致最终报错
问题解决
推荐的解决办法是遵守PageHelper的使用规范, 在分页和执行SQL之间不要有其他的内容, 防止万一, 从根本上避免异常发生
也可以手动从PageHelper的ThreadLocal中移除当前线程的信息, 通过Aop或者抓异常啥的, 但是这个就比较low了