问题重现
开发环境Spring Boot + Mysql + mybatis+ pagehelper
开发中碰到莫名其妙的错误, 一个普通的分页查询, 莫名抛出错误
Cause: com.github.pagehelper.PageException: 处理排序失败: net.sf.jsqlparser.JSQLParserException
...
Caused by: com.github.pagehelper.PageException: 处理排序失败: net.sf.jsqlparser.JSQLParserException
...
Caused by: net.sf.jsqlparser.JSQLParserException: null
...
Caused by: net.sf.jsqlparser.parser.ParseException: Encountered unexpected token: "?" "?"
at line 10, column 50.
Was expecting one of:
"&"
"."
"::"
";"
"<<"
">>"
"AND"
"CONNECT"
"ESCAPE"
"EXCEPT"
"FOR"
"GROUP"
"HAVING"
"INTERSECT"
"MINUS"
"ORDER"
"START"
"UNION"
"^"
"|"
<EOF>
经过不同重试, 发现在模糊查询的条件有值且传入了排序字段, 错误会稳定重现, 遂查找相关代码(代码有所简化)分析:
pom.xml
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.9</version>
</dependency>
xxxServiceImpl.java
@Override
public PagerVo<Vo> list(Form form){
PageHelper.startPage(form.getPageNum(),
form.getPageSize(),
form.getOrderByString());
List<model> lists=xxxMapper.list(form);
PagerVo<Model> resultVo = new PagerVo<>(lists,
new PageInfo(lists).getTotal());
return resultVo;
}
xxxMapper.xml
<select id="list" resultMap="insuranceOrderListVO">
select xxx,xxx,xxx
from table1 a
left join table2 b on a.xxx=b.id
WHERE 1=1
<if test= "condition1 != 0">
AND a.condition=#{condition1}
</if>
<if test= "condition2!= null">
AND b.condition like "%"#{condition2}"%"
</if>
</select>
问题分析
注意到最开始报错, 是SQL不标准, 报错的包名为net.sf.jsqlparser, 是一个处理SQL的工具包, 具体错误为传入的sql中间存在其不能处理的字符, 遂开始检查具体的sql写法.
此时聚焦到 like 的条件拼接, "%"#{condition2}"%", 注意到此写法并非标准的sql写法, 猜测为mybatis对其进行了预处理, 此预处理可能与分页插件所用的SQL处理冲突, 为了验证猜想, 将其对应的sql语句 "%"#{condition2}"%"
更换一种写法:concat("%",#{condition2},"%")
, 并在日志中加入其最终执行进行调试.
修改前-1: 传入"%"#{condition2}"%"+无排序字段(可以顺利执行)
select count(0) from
(select xxx,xxx,xxx
from table1 a
left join table2 b on a.xxx=b.id
WHERE 1=1
AND b.condition like "%"?"%")
tmp_count
修改前2: 传入"%"#{condition2}"%"+有排序字段(抛出错误)
select count(0) from
(select xxx,xxx,xxx
from table1 a
left join table2 b on a.xxx=b.id
WHERE 1=1
AND b.condition like "%"?"%")
tmp_count
修改前-3: 不传入"%"#{condition2}"%"+有排序字段(可以顺利执行)
SELECT count(0)
from table1 a
left join table2 b on a.xxx=b.id
WHERE 1=1
修改后: concat("%",#{condition2},"%")+传入排序字段
SELECT count(0)
from table1 a
left join table2 b on a.xxx=b.id
WHERE 1=1
AND b.condition like concat("%", ?, "%")
比较修改前-2和修改前-3的执行sql, 发现在pagehelper计算总数的时候, 的确对传入的SQL进行了优化, 在计数sql执行时, 移除了不必要的返回字段列, 缩短了sql语句的长度, 当其解析sql语句结构失败时, 会将传入的整个sql语句当成普通sql语句处理;
比较修改前-1和修改前-2的执行sql, 当传入了排序字段时, 处理排序字段时, 其使用的SQL解析工具jsqlparser不支持含有预处理的sql语句, 导致了最终执行结果抛错.
解决方案
条件参数使用like时不要使用"%"#{condition2}"%"
此种可能会导致预处理的写法, 可能由于不是标准的SQL语句导致其他处理方法抛出错误, 在mapper.xml中尽量使用兼容的SQL语句.
参考
https://blog.csdn.net/weixin_36146275/article/details/79355544
网友评论