不規範使用PageHelper導致線程污染出現報錯

問題復現:

在原有項目基礎上開發獲取最新的第一個模板的接口。接口中只有一個查詢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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章