baomidou / mybatis-plus

An powerful enhanced toolkit of MyBatis for simplify development
https://baomidou.com
Apache License 2.0
16.33k stars 4.3k forks source link

严重问题: 查询条件全部丢失 #6312

Closed xuqiangwei closed 2 months ago

xuqiangwei commented 3 months ago

当前使用版本 3.5.7 当前环境信息 Java8 + Mysql8

描述bug现象 sql查询条件全部丢失 提供问题复现步骤

  1. 业务写了一个拼接sql的逻辑如下, 这个拼接会在执行的时候报错, 就版本这样写不会报错, 新版本就会报错 com.baomidou.mybatisplus.core.conditions.query.QueryWrapper queryWrapper queryWrapper.apply("field1 = field2", "");

异常触发点: com.baomidou.mybatisplus.core.conditions.AbstractWrapper#formatSqlMaybeWithParam 513行

  1. 业务写了一个mybatis的拦截器, 用来记录sql的执行时长, 部分代码如下, 这个方法会触发第一步的报错, 但是异常被忽略了 try{ org.apache.ibatis.mapping.MappedStatement mappedStatement appedStatement.getBoundSql(parameterObject).getSql() }catch (Throwable e) { //ignored }
  2. 真正执行业务查询的时候, 查询条件全部丢失

问题点: com.baomidou.mybatisplus.core.conditions.segments.MergeSegments#getSqlSegment 这个方法内, cacheSqlSegment 在未拼接完整sql的时候就赋值为true, 第一次查询异常, sql拼接失败, 第二次查询的时候, 直接返回错误的sql

提供完整堆栈日志(可选)

提供问题复现工程(可选) 请尽量提供复现工程,减少大家排错的时间.

nieqiurong commented 3 months ago

提供复现工程.

xuqiangwei commented 3 months ago

提供复现工程.

com.baomidou.mybatisplus.core.conditions.segments.MergeSegments#getSqlSegment 这个方法内, cacheSqlSegment 在未拼接完整sql的时候就赋值为true. 这个问题在 sql 拼接结束后再赋值cacheSqlSegment为true

miemieYaho commented 2 months ago

你是多线程query使用的同一个wrapper?

xuqiangwei commented 2 months ago

你是多线程query使用的同一个wrapper?

平台有mybatis拦截器,用来监控sql执行情况,平台没有阻断异常,所以复用了wrapper

miemieYaho commented 2 months ago
  1. 你说的旧版本不报错是什呢版本?这个逻辑一直都是这样,没有参数就不能在后面加参数
  2. 'MergeSegments'这个类设计没问题,你以为放后面再执行一次就你现在的代码他就不报错了吗?
VampireAchao commented 2 months ago

Please provide a Minimimal Reproducable Example, preferable as a Github repository. Make sure to include the database, either as an in memory database or if that is not possible using Testcontainers.

请提供一个最小可复现示例,最好作为一个 Github 仓库。请确保包括数据库,如果无法使用内存数据库,可以使用 Testcontainers

xuqiangwei commented 2 months ago
  1. 你说的旧版本不报错是什呢版本?这个逻辑一直都是这样,没有参数就不能在后面加参数
  2. 'MergeSegments'这个类设计没问题,你以为放后面再执行一次就你现在的代码他就不报错了吗?
  1. 3.4.2, 我们最近在升级, 升级后就报错了
  2. 缓存逻辑没问题, cacheSqlSegment 赋值的时机不对. 我们代码本身问题导致报错, 会阻断sql执行, 现在重复调用相同方法, 第二次没有报错, 导致的问题是查询条件全部丢失了. 对于新功能开发这种问题应该可以避免, 但是像我们这样升级上来出现的异常情况, 很难在升级后就能发现问题, 只有特定的场景才会触发. 我的建议是把 cacheSqlSegment = true 放到 return 前, 这样保证了方法的幂等.
miemieYaho commented 2 months ago

本身就是单线程应用,不存在你说的幂等,就算放你说的地方那还是照样会报错,你自己把报错异常吞掉导致的问题那是你的事

miemieYaho commented 2 months ago

后面的版本加强了参数校验 3.4.2都3年前的版本了,请遵照正确的使用方式使用