日期
版本
作者
说明
2023-07-08
V-1.0
孔留锋
文档创建。
概要 简介 项目基于RuoYi-Vue前后端分离版本3.8.1。现需要将版本升级到最新版本3.8.6。
升级内容 组件升级 druid、fastjson、pagehelper、oshi、kaptcha
实施 1.主POM文件修改 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <properties > <druid.version > 1.2.16</druid.version > <kaptcha.version > 2.3.3</kaptcha.version > <pagehelper.boot.version > 1.4.6</pagehelper.boot.version > <fastjson.version > 2.0.34</fastjson.version > <oshi.version > 6.4.3</oshi.version > </properties > <dependencyManagement > <dependency > <groupId > pro.fessional</groupId > <artifactId > kaptcha</artifactId > <version > ${kaptcha.version}</version > </dependency > </dependencyManagement >
2.framework模块POM文件修改 1 2 3 4 5 6 7 8 9 10 11 12 13 <dependencies > <dependency > <groupId > pro.fessional</groupId > <artifactId > kaptcha</artifactId > <exclusions > <exclusion > <artifactId > javax.servlet-api</artifactId > <groupId > javax.servlet</groupId > </exclusion > </exclusions > </dependency > </dependencies >
3.重启异常问题 1 2 3 4 5 6 21:54:29.546 [http-nio-8080-exec-100] DEBUG c.r.s.m.S.selectPage_mpCount - [debug,137] - ==> Preparing: SELECT COUNT() FROM sys_user WHERE (del_flag = ?) ### Error querying database. Cause: java.sql.SQLSyntaxErrorException: 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 ') FROM sys_user WHERE (del_flag = '0')' at line 1 ### The error may exist in com/ruoyi/system/mapper/SysUserMapper.java (best guess) ### The error may involve defaultParameterMap ### The error occurred while setting parameters ### SQL: SELECT COUNT() FROM sys_user WHERE (del_flag = ?)
4.问题排查及解决 问题描述 Mybatis-plus 分页,count 时候没有传入count(1) 或count(*) ,注入的是count() ,导致语法错误。怀疑给升级的pagehelper版本有问题,pagehelper版本由1.4.1升级到1.4.6.
版本退回1.4.1,发现果然没有报错。
最终解决方案 版本继续升级到1.4.6,断点打在查询语句如下地方。
1 Page<SysUser> pageResutl = iSysUserService.page(page, query);
跟踪发现,进入PaginationInnerInterceptor 类,autoCountSql方法,具体如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 protected String autoCountSql (boolean optimizeCountSql, String sql) { if (!optimizeCountSql) { return lowLevelCountSql(sql); } try { Select select = (Select) CCJSqlParserUtil.parse(sql); PlainSelect plainSelect = (PlainSelect) select.getSelectBody(); Distinct distinct = plainSelect.getDistinct(); GroupByElement groupBy = plainSelect.getGroupBy(); List<OrderByElement> orderBy = plainSelect.getOrderByElements(); if (CollectionUtils.isNotEmpty(orderBy)) { boolean canClean = true ; if (groupBy != null ) { canClean = false ; } if (canClean) { for (OrderByElement order : orderBy) { Expression expression = order.getExpression(); if (!(expression instanceof Column) && expression.toString().contains(StringPool.QUESTION_MARK)) { canClean = false ; break ; } } } if (canClean) { plainSelect.setOrderByElements(null ); } } for (SelectItem item : plainSelect.getSelectItems()) { if (item.toString().contains(StringPool.QUESTION_MARK)) { return lowLevelCountSql(select.toString()); } } if (distinct != null || null != groupBy) { return lowLevelCountSql(select.toString()); } if (optimizeJoin) { List<Join> joins = plainSelect.getJoins(); if (CollectionUtils.isNotEmpty(joins)) { boolean canRemoveJoin = true ; String whereS = Optional.ofNullable(plainSelect.getWhere()).map(Expression::toString).orElse(StringPool.EMPTY); whereS = whereS.toLowerCase(); for (Join join : joins) { if (!join.isLeft()) { canRemoveJoin = false ; break ; } FromItem rightItem = join.getRightItem(); String str = "" ; if (rightItem instanceof Table) { Table table = (Table) rightItem; str = Optional.ofNullable(table.getAlias()).map(Alias::getName).orElse(table.getName()) + StringPool.DOT; } else if (rightItem instanceof SubSelect) { SubSelect subSelect = (SubSelect) rightItem; if (subSelect.toString().contains(StringPool.QUESTION_MARK)) { canRemoveJoin = false ; break ; } str = subSelect.getAlias().getName() + StringPool.DOT; } str = str.toLowerCase(); String onExpressionS = join.getOnExpression().toString(); if (onExpressionS.contains(StringPool.QUESTION_MARK) || whereS.contains(str)) { canRemoveJoin = false ; break ; } } if (canRemoveJoin) { plainSelect.setJoins(null ); } } } plainSelect.setSelectItems(COUNT_SELECT_ITEM); return select.toString(); } catch (JSQLParserException e) { logger.warn("optimize this sql to a count sql has exception, sql:\"" + sql + "\", exception:\n" + e.getCause()); } catch (Exception e) { logger.warn("optimize this sql to a count sql has error, sql:\"" + sql + "\", exception:\n" + e); } return lowLevelCountSql(sql); }
执行 plainSelect.setSelectItems(COUNT_SELECT_ITEM);的时候获取的是空,进入SelectExpressionItem类,发现来源于jsqlparser 包,版本为4.5. 版本退回1.4.1,发现jsqlparser版本为4.2 。
解决方案一,住pom文件中指定jsqlparser版本 ,版本降级。
1 2 3 4 5 6 7 8 9 10 11 <properties > <jsqlparser > 4.2</jsqlparser > </properties > <dependencyManagement > <dependency > <groupId > com.github.jsqlparser</groupId > <artifactId > jsqlparser</artifactId > <version > ${jsqlparser}</version > </dependency > </dependencyManagement >
扩展与思考 扩展 登录Maven 参考 https://central.sonatype.com/,查看最新版本jsqlparser。
尝试升级4.6版本,报错。 继续Maven版本查看。
mybatis-plus 版本为 3.4.2 执行 PaginationInnerInterceptor 注入 count 时候如下:
1 2 3 4 5 6 7 8 9 10 protected static final List<SelectItem> COUNT_SELECT_ITEM = Collections.singletonList(defaultCountSelectItem());private static SelectItem defaultCountSelectItem () { Function function = new Function (); function.setName("COUNT" ); function.setAllColumns(true ); return new SelectExpressionItem (function); }
jsqlparser包中 Function 不同版本的toString 对 count 的处理方式,也就是说从4.3版本开始就已经支持了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public String toString () { String params; if (this .parameters == null && this .namedParameters == null ) { if (this .isAllColumns()) { params = "(*)" ; } else { params = "()" ; } } return ans; } public String toString () { String params; if (this .parameters == null && this .namedParameters == null ) { params = "()" ; } return ans; }
查看系统中使用的mybatis-pulus3.4.2版本默认的支持
常看mybatis-plus 版本发布
jsqlparser 4.3版本是2021年12月12日发布, 看mybatis-plus3.5.0版本,已经PaginationInnerInterceptor类
mybatis-plus升级支持了对最新的jsqlparser的升级。 还可以选择升级mybatis-plus版本,但风险点有点高,放弃。
mybatis-plus版本
jsqlparser默认版本
3.4.2
4.0
…
3.5.0
4.3
思考 一些项目在做的时候相关组件不是最新版本,项目可能持续几年,后面会发现各个组件都已经升级。并且不同组件之间存在着 多组件 版本不一致问题。
建议,大框架除非官方发布由重大问题的,项目系统稳定的情况下不建议升级,否则会出现不可预见问题。如springboot最新版本都干到3.1.1 了。 对于ruoyi框架本省 3.8.1对应springboot2.5.10,3.8.6对应springboot2.5.15, 因考虑因素太多升级也很慎重。