Mybatis 缓存
Mybatis 中有一级缓存和二级缓存,默认情况下一级缓存是开启的,而且是不能关闭的。一级缓存是指 SqlSession 级别的缓存,当在同一个 SqlSession 中进行相同的 SQL 语句查询时,第二次以后的查询不会从数据库查询,而是直接从缓存中获取,一级缓存最多缓存 1024 条 SQL。二级缓存是指可以跨 SqlSession 的缓存。是 mapper 级别的缓存,对于 mapper 级别的缓存不同的sqlsession 是可以共享的。
第一次发出一个查询 sql,sql 查询结果写入 sqlsession 的一级缓存中,缓存使用的数据结构是一个 map。
key:MapperID+offset+limit+Sql+所有的入参
value:用户信息
同一个 sqlsession 再次发出相同的 sql,就从缓存中取出数据。如果两次中间出现 commit 操作(修改、添加、删除),本 sqlsession 中的一级缓存区域全部清空,下次再去缓存中查询不到所以要从数据库查询,从数据库查询到再写入缓存。
@Test
public void test002() {
SqlSession sqlSession = MyBatisTools.getSqlSession();
UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
Users users1 = usersMapper.getUserById(1);
System.out.println("Users1==" + users1);
//新建了一个sqlSession
SqlSession sqlSession2 = MyBatisTools.getSqlSession();
UsersMapper usersMapper2 = sqlSession2.getMapper(UsersMapper.class);
Users users2 = usersMapper2.getUserById(1);
System.out.println("Users2==" + users2);
System.out.println("users1与users2是否相等:" + (users1 == users2));
sqlSession.close();
sqlSession2.close();
}
可以看到执行结果获取的两个对象已经不相等,一级缓存已经失效。
@Test
public void test003() {
SqlSession sqlSession = MyBatisTools.getSqlSession();
UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
Users users1 = usersMapper.getUserById(1);
System.out.println("Users1==" + users1); //两次查询中间执行数据增加、修改或删除操作
Users users = new Users();
users.setName("Lisa");
users.setPwd("123456");
usersMapper.addUser(users);
Users users2 = usersMapper.getUserById(1);
System.out.println("Users2==" + users2);
System.out.println("users1与users2是否相等:" + (users1 == users2));
sqlSession.commit();
sqlSession.close();
}
执行结果如下:
@Test
public void test004() {
SqlSession sqlSession = MyBatisTools.getSqlSession();
UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
Users users1 = usersMapper.getUserById(1);
System.out.println("Users1==" + users1);
/手动刷新用户一级缓存, 导致用户一级缓存原有的内容消失掉
sqlSession.clearCache();
Users users2 = usersMapper.getUserById(1);
System.out.println("Users2==" + users2);
System.out.println("users1与users2是否相等:" + (users1 == users2));
sqlSession.close();
}
二级缓存的范围是 mapper 级别(mapper 同一个命名空间),mapper 以命名空间为单位创建缓存数据结构,结构是 map。mybatis 的二级缓存是通过 CacheExecutor 实现的。CacheExecutor其实是 Executor 的代理对象。所有的查询操作,在 CacheExecutor 中都会先匹配缓存中是否存在,不存在则查询数据库。
key:MapperID+offset+limit+Sql+所有的入参
具体使用需要配置:
@Test
public void test006() {
SqlSession sqlSession = MyBatisTools.getSqlSession();
UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
Users users1 = usersMapper.getUserById(1);
System.out.println("Users1==" + users1);
sqlSession.close();
SqlSession sqlSession3 = MyBatisTools.getSqlSession();
UsersMapper usersMapper3 = sqlSession3.getMapper(UsersMapper.class);
Users users = new Users();
users.setName("Lily");
users.setPwd("123456");
usersMapper3.addUser(users);
sqlSession3.commit();
sqlSession3.close();
//新建一个sqlSession
SqlSession sqlSession2 = MyBatisTools.getSqlSession();
UsersMapper usersMapper2 = sqlSession2.getMapper(UsersMapper.class);
Users users2 = usersMapper2.getUserById(1);
System.out.println("Users2==" + users2);
sqlSession2.close();
System.out.println("users1与users2是否相等:" + (users1 == users2));
}
测试结果:可以看到如下图执行了两次SQL,说明二级缓存失效
<select id="getUserById" parameterType="integer" resultType="net.togogo.pojo.Users" useCache="false"> select * from users where id=#{id}
</select>
<select id="findAll" resultMap="userMap" useCache="false" flushCache="true">
select * from user u left join orders o on u.id = o.uid
</select>