問題復現:
在原有項目基礎上開發獲取最新的第一個模板的接口。接口中只有一個查詢sql:select x from x where x limit 1。
調試總是報錯:
org.springframework.jdbc.BadSqlGrammarException: ### Error querying database. Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'LIMIT 10000' at line 5 ### The error may exist in class path resource [mapper/AlipayCardTemplateMapper.xml] ### The error may involve defaultParameterMap ### The error occurred while setting parameters ### SQL: select template_id,callback from alipay_card_template order by pkno desc limit 1 LIMIT ? ### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'LIMIT 10000' at line 5 ; bad SQL grammar []; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'LIMIT 10000' at line 5 at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:234) ~[spring-jdbc-5.1.6.RELEASE.jar!/:5.1.6.RELEASE] at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72) ~[spring-jdbc-5.1.6.RELEASE.jar!/:5.1.6.RELEASE] at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:73) ~[mybatis-spring-1.3.2.jar!/:1.3.2] at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:446) ~[mybatis-spring-1.3.2.jar!/:1.3.2] at com.sun.proxy.$Proxy128.selectOne(Unknown Source) ~[na:na] at org.mybatis.spring.SqlSessionTemplate.selectOne(SqlSessionTemplate.java:166) ~[mybatis-spring-1.3.2.jar!/:1.3.2]
發現打印sql語句,莫名後面多追加了LIMIT 10000導致報錯,可能是其他地方分頁影響到了,ThreadLocal線程污染。
最後排查,找到是有一個接口前面使用PageHelper.startPage(page, size);,後面並沒有mapper查詢,而是調用的遠程接口查詢。並且經過前後端搜索,發現pageSize=10000的參數只有這個接口。
很快定位接口,並修改:
在原有邏輯上加上try catch 並在finally中手動clearPage。
try { PageHelper.startPage(page, size); // 原有邏輯調用遠程接口查詢 。。。 PageInfo<String> pageInfo = new PageInfo<>(cusTags); 。。。 }catch (Exception e){ log.error("queryCusTags,異常:",e); return new ResponseObjectResult(new ResponseStatus(ResultCode.FAIL)); }finally { /** * 1.原因:分頁後面沒有緊跟mapper調用,而是調用遠程接口返回列表。mybatis沒有走攔截器不會自動PageHelper.clearPage()。需要手動PageHelper.clearPage(); * 否則會出現線程污染導致報錯(getTemplateInfo()莫名後面多追加了LIMIT 10000導致報錯,可能是其他地方分頁影響到了,ThreadLocal線程污染。)。 * 2.復現:開發環境/getTemplateInfo接口去掉PageHelper.clearPage()。手機頁面連續點擊領取會員卡(調用的是/getTemplateInfo接口),postman同時連續請求/queryCusTags。 * 發現/getTemplateInfo接口報錯BadSqlGrammarException:limit 1 LIMIT ? 。多追加了個LIMIT ?。 * 3.修改爲此處在finally中手動clear。再次重複步驟2多次,未再出現連續點擊‘領取會員卡’按鈕報錯。 */ PageHelper.clearPage(); }
修改後再次測試多遍,未發現錯誤。
看項目中有好幾個地方在查詢前都主動clearPage。估計是沒找到產生的根源在哪兒,查詢前加clearPage最簡單有效。如果找到根源,那麼其他地方完全不用加clearPage也不會出現報錯。
參考:
https://www.jianshu.com/p/17ddc714b57f