当前使用版本(必填,否则不予处理)
3.1.2 、 3.5.1
该问题是如何引起的?(确定最新版也有问题再提!!!)
sqlSource.getBoundSql() 随机解析不出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
这个问题让我很不解,当我条件断点调试时,
,这里面条件已经是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)时使用