当前使用版本(必填,否则不予处理)

3.1.2 、 3.5.1

该问题是如何引起的?(确定最新版也有问题再提!!!)

sqlSource.getBoundSql() 随机解析不出where条件

MyBatis-Plus 【BUG紧急】sqlSource.getBoundSql() 返回的sql没有解析出where子句

MyBatis-Plus 【BUG紧急】sqlSource.getBoundSql() 返回的sql没有解析出where子句

重现步骤(如果有就写完整)

MyBatis-Plus 【BUG紧急】sqlSource.getBoundSql() 返回的sql没有解析出where子句

报错信息

Comment From: aryout

@miemieYaho

Comment From: nancheung

有具体复现步骤或者demo有吗?

Comment From: aryout

有图里就有,我把代码粘出来

@PostMapping(value = "hello")
@ResponseBody
public String helloMock(){
    try {
        // 找一个表,模拟构造参数,我猜动态SQL才会在解析出出问题::DynamicSqlSource
        QueryWrapper<PersonRankDO> doQueryWrapper = new QueryWrapper<>();
        doQueryWrapper.lambda().eq(PersonRankDO::getBizType, "gmis");

        MapperMethod.ParamMap paramMap = new MapperMethod.ParamMap();
        paramMap.put("ew", doQueryWrapper);
        paramMap.put("param1", doQueryWrapper);

        Runnable runnable = () -> {
            int noWhere = 0;
            for (int i = 0; i < 100; i++) {
                // DynamicSqlSource, MixedSqlNode
                // 使用basemapper的selecrList方法
                MappedStatement m =  sqlSessionFactory.getConfiguration()
                        .getMappedStatement("com.xxx.dao.mapper.PersonRankMapper.selectList");

                // 统计出,不解析出where的次数
                if (!m.getBoundSql(paramMap).getSql().replace("\n","").contains("WHERE")) noWhere++;
            }
            System.out.println(Thread.currentThread().getName() + " :: "+ noWhere);
        };
        // 注意,多线程是为了更容易复现问题,但我确定我最开始遇到问题时都是单次请求的,
        // 所以单线程也会出问题,只不过抽出该方法来测试时候单线程又不太容易复现
        new Thread(runnable, "A").start();
        new Thread(runnable, "B").start();

        //List<PersonRankDO> list = personRankMapper.selectList(doQueryWrapper);
        //System.out.println(JSON.toJSONString(list));
    } catch (Exception e) {
        e.printStackTrace();
    }
    return "ok";
}

Comment From: aryout

anybody😯 @miemieYaho @nancheung97 @yangyang0507

Comment From: jojocodeX

这个问题让我很不解,当我条件断点调试时, MyBatis-Plus 【BUG紧急】sqlSource.getBoundSql() 返回的sql没有解析出where子句,这里面条件已经是false,但是当我再次调用上面计算方法时,结果为true,是不是和OGNL解析有关 ,

Comment From: VampireAchao

QueryWrapper不要在多个线程中复用,写成这样即可:

package com.ruben.mybatisplusissue;

import javax.annotation.Resource;

import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruben.mybatisplusissue.entity.User;

import lombok.SneakyThrows;

/**
 * @author VampireAchao<achao1441470436@gmail.com>
 * @since 2022/4/20 13:07
 */
@SpringBootTest
class GithubIssue4412 {

    @Resource
    private SqlSessionFactory sqlSessionFactory;

    @SneakyThrows
    @Test
    void test() {
            Runnable runnable = () -> {
                int noWhere = 0;
                for (int i = 0; i < 100; i++) {
                    // DynamicSqlSource, MixedSqlNode
                    // 使用basemapper的selecrList方法
                    MappedStatement m = sqlSessionFactory.getConfiguration()
                            .getMappedStatement("com.ruben.mybatisplusissue.mapper.UserMapper.selectList");
                    QueryWrapper<User> doQueryWrapper = new QueryWrapper<>();
                    doQueryWrapper.lambda().eq(User::getId, 1L);
                    MapperMethod.ParamMap paramMap = new MapperMethod.ParamMap();
                    paramMap.put("ew", doQueryWrapper);
                    paramMap.put("param1", doQueryWrapper);
                    // 统计出,不解析出where的次数
                    if (!m.getBoundSql(paramMap).getSql().replace("\n", "").contains("WHERE")) noWhere++;
                }
                System.out.println(Thread.currentThread().getName() + " :: " + noWhere);
            };
            new Thread(runnable, "A").start();
            new Thread(runnable, "B").start();
           Thread.currentThread().join();
    }

}

Comment From: aryout

@jojocodeX @VampireAchao

辛苦各位了 ,最后发现是因为我们的一个基础封装工具包,使用切面拦截了sql方法,并对参数进行多线程操作而引起的。 当然,这是发现了原因,但是为什么多线程操作这个入参对象会造成影响,因为我看了下这个入参及周边的sqlnode等等对象,基本都是read/get操作,没发现set操作,深层次的原因还需要慢慢细看。

另外呢,很多项目都会对sql操作进行一些拦截处理,很容易造成这个场景复现。建议官方能保证这个意外不会发生,比如ThreadLocal维护一个深拷贝,在m.getBoundSql(paramMap)时使用

MyBatis-Plus 【BUG紧急】sqlSource.getBoundSql() 返回的sql没有解析出where子句