目录
3.2、使用sqlSession.clearCache()方法(推荐)
一、问题描述
多次查询相同的数据库记录,但每次查询返回的对象是同一个实例的引用,例如Demo示例:
@SpringBootTest
class MybatisApplicationTests {
@Resource
private UserMapper userMapper;
@Test
@Transactional
void contextLoads() {
User user = userMapper.selectUserByUsername("张三");
user.setUsername("李四");
User user2 = userMapper.selectUserByUsername("张三");
Date date = new Date();
}
}
执行结果:
张三的原密码是123456,我想把它的密码修改为129181367。
在这个方法中,我查询了两次名为张三的用户,第一次查询的结果我把张三的密码进行了set,但是我并没有进行任何的update操作,于是我又查询了一次名为张三的用户,发现第二次查询的结果竟然和我set后的数据一致,但道理应该是不一致的。
二、问题原因
经过我反复研究和测试,先说结论是缓存导致的问题,因为MyBatis的一级缓存是默认开启的,在同一事务中(我加了@Transactional这个注解),相同的查询只会返回缓存中的对象,而不会从数据库中重新加载,换而言之,这2个对象指向的都是同一个对象地址,是同一个实例,而不是新的实例。
三、解决方案
3.1、去除@Transactional这个注解(不推荐)
不过这个办法不推荐,因为在一些特定场景中我们需要保证事务的一致性,虽然去掉了可以解决查询结果不一致的问题,但是牺牲了事务的一致性,如下图所示:
3.2、使用sqlSession.clearCache()方法(推荐)
在执行插入、更新或删除等操作后,使用sqlSession.clearCache() 方法手动清理本地Session缓存,以确保后续查询可以获取到最新的数据。
注入这个jar包下面的SqlSession;
import org.apache.ibatis.session.SqlSession;
@Resource
private SqlSession sqlSession;
调用方法:
sqlSession.clearCache();
这样就可以完美解决了。