3.0.6
saveBatch方法会导致一级缓存无法被清除,第二次查询不会发出sql查询
如下代码,在一个事务中:
//查询列表,能查到1条数据
List<TaskEo> taskEoList = taskMapper.selectList(new QueryWrapper<TaskEo>().eq("farm_id", -1025));
Assert.assertEquals(1, taskEoList.size());
//插入数据
taskService.saveBatch(taskEoList);
//同样条件再次查询,只能查到1条数据,日志中也没有打印sql语句
taskEoList = taskMapper.selectList(new QueryWrapper<TaskEo>().eq("farm_id", -1025));
Assert.assertEquals(2, taskEoList.size()) ; //这里断言异常:java.lang.AssertionError: Expected :2 Actual :1
如上代码,数据库本来有一条数据,调用saveBatch方法后(taskService实现了IService接口),再次查询,发现只有一条数据,而实际数据库是有两条数据的。
在第二次查询前手动清除sqlSession的缓存,则能正常查出两条数据,代码如下:
//查询列表,能查到1条数据
List<TaskEo> taskEoList = taskMapper.selectList(new QueryWrapper<TaskEo>().eq("farm_id", -1025));
Assert.assertEquals(1, taskEoList.size());
//插入数据
taskService.saveBatch(taskEoList);
//手动清除sqlSession缓存
sqlSession.clearCache();
//同样条件再次查询,能查到2条数据,日志中有打印sql语句
taskEoList = taskMapper.selectList(new QueryWrapper<TaskEo>().eq("farm_id", -1025));
Assert.assertEquals(2, taskEoList.size()) ; //正常
在saveBatch方法中会重新创建SqlSession对象,和外部的SqlSession不是同一个实例,从而导致外部的SqlSession缓存无法被清除,再次查询时会使用缓存而不去查数据库。
分页的时候也会触发类似的 bug,不过分页的这个从 MP 这层来说不是太容易解决
如果插入的SQL能做成下面这样这个问题可能就会好处理一些:
INSERT INTO table VALUES
(1, 2, 3),
(4, 5, 6),
(7, 8, 9);
因为这样就不需要一个执行类型是BATCH的SqlSession了
目前我这边的解决方法是重写saveBatch方法,通过@Autowire注解获取到sqlSession对象,手动调用sqlSession.clear()方法来清除缓存
分页的时候也会触发类似的 bug,不过分页的这个从 MP 这层来说不是太容易解决
没有用到MP的分页,很好奇分页的时候触发的是什么bug?
分页的时候也会触发类似的 bug,不过分页的这个从 MP 这层来说不是太容易解决
没有用到MP的分页,很好奇分页的时候触发的是什么bug?
第一次请求,分页流程:
第二次请求,分页流程:
SQL,拦截器大概是没拦到,于是总记录数为 0目前我的解决方案是:每次请求开始的时候由拦截器做清空缓存
这大概是2.x时遇到的问题,目前项目一直带着拦截器,因此并不清楚新版本是否解决了这个问题
或者在批量处理的最后面加一行,清空主 SqlSession 的一级缓存也可以
虽然不是个完美的解决方案
我也遇到了这个问题,请问有其它解决方案吗。
可以尝试手动清除一级缓存
可以尝试手动清除一级缓存
老哥,能看下cat邮箱的邮件吗?我有一个关于sqlSession的疑问还望请教。
Most helpful comment
第一次请求,分页流程:
第二次请求,分页流程:
SQL,拦截器大概是没拦到,于是总记录数为 0目前我的解决方案是:每次请求开始的时候由拦截器做清空缓存
这大概是
2.x时遇到的问题,目前项目一直带着拦截器,因此并不清楚新版本是否解决了这个问题