不规范使用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

 

posted @ 2023-03-03 11:53  super超人  阅读(334)  评论(0编辑  收藏  举报