在使用Ruoyi管理系统中出现这个问题

Error querying database. Cause: java.sql.SQLSyntaxErrorException: Unknown column 'xxx_time' in 'where clause'

因为对应报错的SQL中没有该字段,前端也没有传入该字段,而且这个问题是偶发的,所以一直也没查到原因。
今天心血来潮追溯了下源码隐约发现了问题所在。

# 首先声明:# 1.先确认是不是确实是字段写错了# 2.这个锅Ruoyi不背,PageHelper也不背,问题肯定就是出在业务代码里。
# 解决方式:# 1.确保PageHelper的startPage方法之后直接执行doSelect,不存在doSelect之前中途返回或者还有其他查询的情况# 2.现有代码中误用太多不方便全改,可以在拦截器返回的时候调用下clearPage清除下缓存

先说下我们的代码场景
1.controller层的list接口调用了Ruoyi封装类PageUtils.startPage()无参方法
2.startPage方法之后调用了service层的业务方法
3.service层的业务方法中对请求参数做了一系列判断,异常则返回,最后执行mybatis里的查询


下面简单分析下原因
先来看下使用的PageUtils.startPage()

/** * 设置请求分页数据 */public static void startPage() {    PageDomain pageDomain = TableSupport.buildPageRequest();    Integer pageNum = pageDomain.getPageNum();    Integer pageSize = pageDomain.getPageSize();    String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());    Boolean reasonable = pageDomain.getReasonable();    PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);}

这个orderBy有点像我在找的东西,追溯一下PageHelper.startPage(pageNum, pageSize, orderBy),里面有这么两个方法

/** * 开始分页 * * @param pageNum  页码 * @param pageSize 每页显示数量 * @param orderBy  排序 */public static  Page startPage(int pageNum, int pageSize, String orderBy) {    Page page = startPage(pageNum, pageSize);    // 这里可疑    page.setOrderBy(orderBy);    return page;}
/** * 开始分页 * * @param pageNum      页码 * @param pageSize     每页显示数量 * @param count        是否进行count查询 * @param reasonable   分页合理化,null时用默认配置 * @param pageSizeZero true且pageSize=0时返回全部结果,false时分页,null时用默认配置 */public static  Page startPage(int pageNum, int pageSize, boolean count, Boolean reasonable, Boolean pageSizeZero) {    Page page = new Page(pageNum, pageSize, count);    page.setReasonable(reasonable);    page.setPageSizeZero(pageSizeZero);    // 当已经执行过orderBy的时候    // 这一段也可疑    Page oldPage = getLocalPage();    if (oldPage != null && oldPage.isOrderByOnly()) {        page.setOrderBy(oldPage.getOrderBy());    }    setLocalPage(page);    return page;}

看代码里找到了这个比较可疑的getLocalPage()方法,然后发现是个ThreadLocal,感觉这里应该是有问题,但是一时半会儿又不知道确切的问题点。

protected static final ThreadLocal LOCAL_PAGE = new ThreadLocal();/*** 获取 Page 参数** @return*/public static  Page getLocalPage() {    return LOCAL_PAGE.get();}

查了下PageHelper线程的问题,发现了这篇文章 又遇PageHelper线程污染,知道了“线程污染”这个词儿,感觉用的很贴切啊。还有这篇文章里链接的另一篇文章也很值得看下 不规范使用PageHelper导致线程污染。


为什么之前在其他springboot项目里没有出现过这个问题,使用了Ruoyi框架之后会出现呢,这和Ruoyi的demo也有点关系,demo是在controller层使用的PageHelper的startPage()无参方法,然后调用service层的查询方法。
这个只适合直接查询数据库的方式使用,而我们直接拿来就用,无脑的往里面添加业务逻辑。功能复杂一点的时候service层的业务代码出现了异常情况可能直接就返回了,没有走到SQL查询。


以上有部分可能不严谨,我分别调试了几种情况。
但是诡异的是,同一套代码反复跑了几遍,结果竟然不一样。。。
突然就感觉 物理学不存在了 遇到薛定谔了。。。
我在拦截器里添加了日志、调用了下PageHelper.clearPage()方法,后续再观察一下吧。