Mybatis的一级缓存和二级缓存
作用域
一级缓存的作用域是session
二级缓存的作用域是namespace
一级缓存
一级缓存交于Executor维护的,在BaseExecutor下有一个PerpetualCache类型的属性,这个就是一级缓存。因为每一个SqlSession都有一个Executor,即代表着,每一个Session都有着独立的一级缓存PerpetualCache。
当用户发起查询请求时,是SqlSession会先去缓存中查找,如果有数据就返回数据,如果,没有就再去数据库查找。
但是,在用户在进行增删改的操作时,此时数据库的数据有改变,此时会清空一级缓存,即执行commit操作时,这是为了保证数据可见性。
public static void main(String[] args) {
try {
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = builder.build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
DormDao mapper = sqlSession.getMapper(DormDao.class);
System.out.println(">>>>>>>>>>>>>>>>>>>>>");
Dorm dorm1 = mapper.selectByPrimaryKey("A1-101");
System.out.println(dorm1);
// System.out.println(">>>>>>>>>>>>>>>>>>>>>");
// Dorm dorm3 = new Dorm();
// dorm3.setId("A1-101");
// dorm3.setDormno("1");
// dorm3.setRoomno("121");
// dorm3.setDormname("A");
// mapper.updateByPrimaryKey(dorm3);
// sqlSession.commit();
System.out.println(">>>>>>>>>>>>>>>>>>>>>");
Dorm dorm2 = mapper.selectByPrimaryKey("A1-101");
System.out.println(dorm2);
} catch (IOException e) {
e.printStackTrace();
}
}
上面的代码在没有进行增删改的时候是第二次查询时使用的缓存,并没有发送sql语句到数据库。不提交时,使用的还是缓存。
二级缓存
二级缓存的配置
-
全局总开关
<!-- 开启二级缓存--> <setting name="cacheEnabled" value="true"/>
-
namespace的开关
<cache/>
-
可在具体的xml语句中禁止使用二级缓存 useCache=flase
配置好二级缓存之后,sqlsession的执行流程变为二级缓存 -> 一级缓存 或者 二级缓存-> 数据库。
二级缓存更像是所有一级缓存的统一,通过一个hashMap将所有一级缓存统一起来,当sqlsession执行是,会先去确认二级缓存中包含的一级缓存的信息,当sqlsession执行commit操作时,会调用tcm的comm犯法方法,此时对应的缓存信息才能被保存到二级缓存中去。
public static void main(String[] args) {
try {
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = builder.build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
SqlSession sqlSession1 = sqlSessionFactory.openSession();
DormDao mapper = sqlSession.getMapper(DormDao.class);
DormDao mapper1 = sqlSession1.getMapper(DormDao.class);
System.out.println(">>>>>>>>>>>>>>>>>>>>>");
Dorm dorm1 = mapper.selectByPrimaryKey("A1-102");
System.out.println(dorm1);
// sqlSession.commit();
System.out.println(">>>>>>>>>>>>>>>>>>>>>");
Dorm dorm4 = mapper1.selectByPrimaryKey("A1-102");
System.out.println(dorm4);
} catch (IOException e) {
e.printStackTrace();
}
}
当没有进行sqlSession.commit()是输出结果如下
>>>>>>>>>>>>>>>>>>>>>
DEBUG [main] - Cache Hit Ratio [com.zelin.MybatisDemo.DormDao]: 0.0
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 1436664465.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@55a1c291]
DEBUG [main] - ==> Preparing: select id, dormname, dormno, roomno from dorm where id = ?
DEBUG [main] - ==> Parameters: A1-102(String)
DEBUG [main] - <== Total: 1
Dorm(id=A1-102, dormname=A, dormno=1, roomno=102)
>>>>>>>>>>>>>>>>>>>>>
DEBUG [main] - Cache Hit Ratio [com.zelin.MybatisDemo.DormDao]: 0.0
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 2147046752.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@7ff95560]
DEBUG [main] - ==> Preparing: select id, dormname, dormno, roomno from dorm where id = ?
DEBUG [main] - ==> Parameters: A1-102(String)
DEBUG [main] - <== Total: 1
Dorm(id=A1-102, dormname=A, dormno=1, roomno=102)
Process finished with exit code 0
可见此时的二级缓存并没有起作用
当进行提交之后sqlSession.commit()输出结果如下
>>>>>>>>>>>>>>>>>>>>>
DEBUG [main] - Cache Hit Ratio [com.zelin.MybatisDemo.DormDao]: 0.0
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 1436664465.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@55a1c291]
DEBUG [main] - ==> Preparing: select id, dormname, dormno, roomno from dorm where id = ?
DEBUG [main] - ==> Parameters: A1-102(String)
DEBUG [main] - <== Total: 1
Dorm(id=A1-102, dormname=A, dormno=1, roomno=102)
>>>>>>>>>>>>>>>>>>>>>
DEBUG [main] - Cache Hit Ratio [com.zelin.MybatisDemo.DormDao]: 0.5
Dorm(id=A1-102, dormname=A, dormno=1, roomno=102)
总结
对网络上的大部分关于一级缓存以及二级缓存的执行流程我提出异议
大部分讲的都是执行流程为
二级 -->一级 -->数据库
而我觉得的执行流程是
二级 -->一级
或者
二级 -->数据库**