记录被mybatis一级缓存坑的问题
- 背景
我之前有个方法需要多次调用数据库拿数据,由于每次查询数据比较少,所以我前期都是直接查数据库拿的,准备后面再改缓存
// 查询代码 假设在A方法中
List<LeftOrderType> leftOrderTypes = orderTypeMapper.selectList(wrapper);
// A方法的后面我对查询到的结果集做了改动,删除了集合中的元素
我是通过其他方法调用A方法去查询的,但是有一天我发现有个方法连续调用了A方法五次,每次只有第一次有结果,后续的四次调用在A方法的查询代码中返回的List都是空的,我查资料说是mybatis一级缓存的问题,但是我这里查询的动作都是在A方法中的,理论上应该是每次调用A方法查询的都是新的集合,但是只有第一次调用有结果,其后续调用都是空集合。
- 原因
后来debug发现每次拿到的集合内存地址都是一样的,说明确实是mybatis缓存生效了,再后来排查发现我调用A方法的方法被打上了@Transactional注解,这下找到原因了,在同一个事务中多次进行相同的查询mybatis会返回第一次查询的结果集(mybatis一级缓存的是结果集的引用),但是我在A方法中对返回的结果集做了修改(删除了结果集的元素),所以后续的几次缓存直接返回这个集合导致拿到的都是空集合。
- 解决方案
- 将mapper的查询放入新构造的集合中,不改动原来的mapper返回的集合
List<LeftOrderType> leftOrderTypes = new ArrayList<>(orderTypeMapper.selectList(wrapper));
- 每次做完操作后清空一级缓存
sqlSession.clearCache();