一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第11天,点击查看活动详情。
MyBatis的缓存
MyBatis的一级缓存
- 一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问
- 使一级缓存失效的四种情况:
- 不同的SqlSession对应不同的一级缓存
- 同一个SqlSession但是查询条件不同
- 同一个SqlSession两次查询期间执行了任何一次增删改操作
- 同一个SqlSession两次查询期间手动清空了缓存
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
cacheMapper mapper = sqlSession.getMapper(cacheMapper.class);
Emp empByEid = mapper.getEmpByEid(1);
System.out.println(empByEid);
// mapper.insert(new Emp(null,"张三",23,"男","123@qq.com"));缓存失效
// sqlSession.clearCache();缓存失效
SqlSession sqlSession1 = SqlSessionUtils.getSqlSession();
cacheMapper mapper1 = sqlSession1.getMapper(cacheMapper.class);
Emp empByEid1 = mapper1.getEmpByEid(1);
System.out.println(empByEid1);
/**
* 可以看到只执行过一次sql,第二次的数据是通过缓存获取的,这是一级缓存得到的,默认开启的,级别是SqlSession的
* 在同一个SqlSession下查到的,都是缓存的,和mapper无关
* DEBUG Preparing: select * from t_emp where eid = ? (BaseJdbcLogger.java:137)
* DEBUG Parameters: 1(Integer) (BaseJdbcLogger.java:137)
* DEBUG 03-21 15:24:15,159 <== Total: 1 (BaseJdbcLogger.java:137)
* Emp{eid=1, empName='张三', age=12, sex='男', email='123@qq.com', dept=null}
* Emp{eid=1, empName='张三', age=12, sex='男', email='123@qq.com', dept=null}
*SqlSession sqlSession = SqlSessionUtils.getSqlSession();
* cacheMapper mapper = sqlSession.getMapper(cacheMapper.class);
* Emp empByEid = mapper.getEmpByEid(1);
* System.out.println(empByEid);
* SqlSession sqlSession1 = SqlSessionUtils.getSqlSession();
* cacheMapper mapper1 = sqlSession1.getMapper(cacheMapper.class);
* Emp empByEid1 = mapper1.getEmpByEid(1);
* System.out.println(empByEid1);
* 这种是执行两次sql语句的,因为是获取了重新的SqlSession
*/
MyBatis的二级缓存
二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被 缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取
二级缓存开启的条件:
a>在核心配置文件中,设置全局配置属性cacheEnabled="true",默认为true,不需要设置
b>在映射文件中设置标签
c>二级缓存必须在SqlSession关闭或提交之后有效
d>查询的数据所转换的实体类类型必须实现序列化的接口
使二级缓存失效的情况:
两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效
b>在映射文件中设置标签
<cache/>
<!-- Emp getEmpByEid(@Param("eid") Integer eid );-->
<select id="getEmpByEid" resultType="Emp">
select * from t_emp where eid = #{eid}
</select>
d>查询的数据所转换的实体类类型必须实现序列化的接口
public class Emp implements Serializable {
public void testCacheTwo(){
try {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
cacheMapper mapper = sqlSession1.getMapper(cacheMapper.class);
System.out.println(mapper.getEmpByEid(1));
sqlSession1.close();
SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
cacheMapper mapper1 = sqlSession2.getMapper(cacheMapper.class);
System.out.println(mapper1.getEmpByEid(1));
sqlSession2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
运行结果:
DEBUG 03-21 16:19:16,807 Cache Hit Ratio [com.aitiguigu.mybatis.mapper.cacheMapper]: 0.0 (LoggingCache.java:60)
DEBUG 03-21 16:19:16,996 ==> Preparing: select * from t_emp where eid = ? (BaseJdbcLogger.java:137)
DEBUG 03-21 16:19:17,031 ==> Parameters: 1(Integer) (BaseJdbcLogger.java:137)
DEBUG 03-21 16:19:17,059 <== Total: 1 (BaseJdbcLogger.java:137)
Emp{eid=1, empName='张三', age=12, sex='男', email='123@qq.com', dept=null}
WARN 03-21 16:19:17,097 As you are using functionality that deserializes object streams, it is recommended to define the JEP-290 serial filter. Please refer to https://docs.oracle.com/pls/topic/lookup?ctx=javase15&id=GUID-8296D8E8-2B93-4B9A-856E-0A65AF9B8C66 (SerialFilterChecker.java:46)
DEBUG 03-21 16:19:17,100 Cache Hit Ratio [com.aitiguigu.mybatis.mapper.cacheMapper]: 0.5 (LoggingCache.java:60)
Emp{eid=1, empName='张三', age=12, sex='男', email='123@qq.com', dept=null}