mybatis LambdaQueryWrapper并发查询问题
·
问题背景
现有一段查询简化如下
IPage<AdminUserDO> page = Page.of(1, 10);
LambdaQueryWrapper<AdminUserDO> query = new LambdaQueryWrapper<>();
query.eq(AdminUserDO::getFirstName, "x");
IPage<AdminUserDO> adminUserDOIPage = adminUserMapper.selectPage(page, query);
分页查询会查两次,先查count再查本页数据
这个查询很慢,就有人进行了优化,优化后简化如下
IPage<AdminUserDO> page = Page.of(1, 10, false);
LambdaQueryWrapper<AdminUserDO> query = new LambdaQueryWrapper<>();
query.eq(AdminUserDO::getFirstName, "x");
IPage<AdminUserDO> adminUserDOIPage = new Page<>();
new Thread(() -> {
adminUserDOIPage.setRecords(adminUserMapper.selectPage(page, query).getRecords());
}).start();
new Thread(() -> {
adminUserDOIPage.setTotal(adminUserMapper.selectCount(query));
}).start();
相当于把查count和查本页数据并发
代码上线后测试发现,快速点击查询,偶尔出现查出来的total不对,正常应该是二十几,偶尔出现几百的情况
问题分析
在日志中查看sql语句,发现total正常情况下,sql语句是对的,包含first_name = 'x’的条件
total异常情况下,没有where条件
说明就是一个偶发问题
在加上有多线程,盲猜一手并发问题,用代码进行验证,编写测试用例如下
LambdaQueryWrapper<AdminUserDO> query = new LambdaQueryWrapper<>();
query.eq(AdminUserDO::getFirstName, "x");
Runnable r = () -> {
TenantContextHolder.setIgnore(true);
System.out.println(adminUserMapper.selectCount(query));
};
new Thread(r).start();
new Thread(r).start();
new Thread(r).start();
new Thread(r).start();
new Thread(r).start();
运行结果如下
发现只有一次是正确带上了查询条件的,其他的都把查询条件丢了(WHERE deleted = 0是框架自动加的不是来自LambdaQueryWrapper的条件),说明LambdaQueryWrapper用过一次过后就把条件清空了?(具体原理需要看源码分析)
问题修复
将LambdaQueryWrapper clone,并发时使用副本操作
LambdaQueryWrapper<AdminUserDO> query = new LambdaQueryWrapper<>();
query.eq(AdminUserDO::getFirstName, "x");
Runnable r = () -> {
System.out.println(adminUserMapper.selectCount(query.clone()));
};
new Thread(r).start();
new Thread(r).start();
new Thread(r).start();
new Thread(r).start();
new Thread(r).start();

问题解决
更多推荐
所有评论(0)