Talk is cheap, Show me the code.
void test() {
/**
* 一级缓存的作用范围session
*/
try (SqlSession session = sqlSessionFactory.openSession()) {
User user = new User();
user.setId(6);
user.setName("test6");
int i = session.insert("addUser", user);
assertEquals(i, 1);
/**
* 本次是从数据库直接读取的,读取之后会存到一级缓存
*
* 没有存入二级缓存,二级缓存需要session.commit()之后才会才会真正保存
* 这也是为什么此处二级缓存没有脏数据的原因
*
* 这里数据库的事务隔离级别是读未提交,所以可以读取到六条数据
*/
List<Object> allUsers = session.selectList("getAllUsers");
assertEquals(allUsers.size(), 6);
// session.commit();
/**
* 这次是直接从一级缓存读取的数据,属于脏数据
* 因为session还没有提交,数据随时有可能回滚
*/
List<Object> allUsers2 = session.selectList("getAllUsers");
assertEquals(allUsers2.size(), 6);
session.rollback();
}
/**
*
* 二级缓存的作用范围:应用程序启动后的一个namespace
*
* 数据回滚之后,依然只读到五条,说明刚才读取的是脏数据
*/
try (SqlSession session = sqlSessionFactory.openSession()) {
List<Object> allUsers = session.selectList("getAllUsers");
assertEquals(allUsers.size(), 5);
}
}
运行日志:
解决mybatis数据脏读方法:
- 彻底关闭一级缓存和二级缓存
- 既然使用一级缓存就不能避免脏数据,我们只有记住只有session提交(session.close方法会执行commit操作)之后读到的数据才可以使用,就能避开这个坑。
- 如果在分布式系统中二级缓存就可能造成脏数据,我们可以使用redis作为缓存嵌入mybatis,这样就可以解决二级缓存脏读问题。