在使用Ruoyi管理系統中出現這個問題 Error querying database. Cause: java.sql.SQLSyntaxErrorException: Unknown column 'xxx_time' in 'where clause' 因為對應報錯的SQL中沒有該欄位,前端也 ...
在使用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 <E> Page<E> startPage(int pageNum, int pageSize, String orderBy) {
Page<E> 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 <E> Page<E> startPage(int pageNum, int pageSize, boolean count, Boolean reasonable, Boolean pageSizeZero) {
Page<E> page = new Page<E>(pageNum, pageSize, count);
page.setReasonable(reasonable);
page.setPageSizeZero(pageSizeZero);
// 當已經執行過orderBy的時候
// 這一段也可疑
Page<E> oldPage = getLocalPage();
if (oldPage != null && oldPage.isOrderByOnly()) {
page.setOrderBy(oldPage.getOrderBy());
}
setLocalPage(page);
return page;
}
看代碼里找到了這個比較可疑的getLocalPage()
方法,然後發現是個ThreadLocal,感覺這裡應該是有問題,但是一時半會兒又不知道確切的問題點。
protected static final ThreadLocal<Page> LOCAL_PAGE = new ThreadLocal<Page>();
/**
* 獲取 Page 參數
*
* @return
*/
public static <T> Page<T> getLocalPage() {
return LOCAL_PAGE.get();
}
查了下PageHelper線程的問題,發現了這篇文章 又遇PageHelper線程污染,知道了“線程污染”這個詞兒,感覺用的很貼切啊。還有這篇文章里鏈接的另一篇文章也很值得看下 不規範使用PageHelper導致線程污染。
為什麼之前在其他springboot項目里沒有出現過這個問題,使用了Ruoyi框架之後會出現呢,這和Ruoyi的demo也有點關係,demo是在controller層使用的PageHelper的startPage()無參方法,然後調用service層的查詢方法。
這個只適合直接查詢資料庫的方式使用,而我們直接拿來就用,無腦的往裡面添加業務邏輯。功能複雜一點的時候service層的業務代碼出現了異常情況可能直接就返回了,沒有走到SQL查詢。
以上有部分可能不嚴謹,我分別調試了幾種情況。
但是詭異的是,同一套代碼反覆跑了幾遍,結果竟然不一樣。。。
突然就感覺 物理學不存在了 遇到薛定諤了。。。
我在攔截器里添加了日誌、調用了下PageHelper.clearPage()
方法,後續再觀察一下吧。