一、简介
缓存是计算机领域非常通用的概念。它介于应用程序和永久性数据存储元(如硬盘上的文件或者数据库)之间,其作用是降低应用程序直接读写永久性数据存储源的频率,从而提高应用的运行性能。缓存中的数据存储源中数据的拷贝,应用程序在运行时直接读写缓存中的数据,只在某些特定时刻按照缓存中的数据来同步更新数据存储源。
缓存的物理介质通常是内存,而永久性数据存储源的物理介质通常是硬盘或磁盘,应用程序读写内在的速度显然比读写硬盘的速度快,如果缓存中存放的数据量非常大,也会用硬盘作为缓存的物理介质。缓存的实现不仅需要作为物理介质的硬件,同时需要用于管理缓存的并发访问和过期策略的软件。因此,缓存是通过软件和硬件共同实现的。
没使用缓存时
使用了缓存
缓存分类
类别 | 说明 |
---|---|
一级缓存 | 事务范围:缓存只能在当前事务访问。缓存的生命周期依赖于事务的生命周期。当事务结束时,缓存也就结束了生命周期。在此范围下,缓存的介质是内存 |
二级缓存 | 进程范围:缓存被进程内的所有事务共享。这些事务有可能是并发访问缓存,因此必须对缓存采取必要的事务隔离机制。缓存的生命周期依赖于进程的生命周期,进程结束时,缓存也就结束了生命周期。进程范围的缓存可能会存放大量的数据,所以存放的介质可以是内存或硬盘 |
三级缓存 | 集群范围:在集群环境中,缓存被一个极其或者多个机器的进程共享。缓存中的数据被复制到集群环境中的每个进程节点,进程间通过远程通信来保证缓存中的数据的一致性,缓存中数据通常采用对象的松散数据形式 |
MyBatis支持1级和2级缓存,在实际开发中,实际上很少使用到MyBatis自带的缓存,大部分情况下,缓存都是使用EHCache,MemoryCache,Redis等等来实现缓存
二、案例
1.一级缓存
@Test
public void test01() throws Exception{
InputStream in = Resources.getResourceAsStream("mybatis-cfg.xml");
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(in);
//事务开始
SqlSession sqlSession = factory.openSession();
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
//第一次查询员工信息 一级缓存中是没有数据的,所以会直接查询数据库中数据
//然后会将数据保存到一级缓存中
List<Emp> emps = mapper.queryEmp();
for (Emp e :
emps) {
System.out.println(e);
}
System.out.println("-----------------------------");
//第二次查询 因为一级缓存中已经存在了要查询的数据,所以就直接返回了,没有数据库查询操作
emps=mapper.queryEmp();
for (Emp e :
emps) {
System.out.println(e);
}
//事务关闭
sqlSession.close();
//重新开启事务
sqlSession=factory.openSession();
mapper = sqlSession.getMapper(EmpMapper.class);
emps = mapper.queryEmp();
for (Emp e :
emps) {
System.out.println(e);
}
}
结果分析
2.二级缓存
二级缓存时基于SqlSessionFactory的,一级缓存的作用于仅仅只是SqlSession,范围比较窄,应用不多,二级缓存时进程级别的,用的就比较多了。二级缓存我们一般使用Redis或者Ehcache来实现。
2.1 引入依赖
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>1.5.0</version>
</dependency>
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.1.0</version>
</dependency>
2.2 开启二级缓存
我们只需要在需要开启的映射文件中添加cache标签即可
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
2.3 测试
@Test
public void test01() throws Exception{
InputStream in = Resources.getResourceAsStream("mybatis-cfg.xml");
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(in);
//事务开始
SqlSession sqlSession = factory.openSession();
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
//第一次查询员工信息 一级和二级缓存中是没有数据的,所以会直接查询数据库中数据
//然后会将数据保存到一级缓存中和二级缓存中
List<Emp> emps = mapper.queryEmp();
for (Emp e :
emps) {
System.out.println(e);
}
System.out.println("-----------------------------");
//第二次查询 因为一级缓存中已经存在了要查询的数据,所以就直接返回了,没有数据库查询操作
emps=mapper.queryEmp();
for (Emp e :
emps) {
System.out.println(e);
}
//事务关闭 会清空一级缓存的数据 但不会清空二级缓存中的数据 直接返回
sqlSession.close();
//重新开启事务
sqlSession=factory.openSession();
mapper = sqlSession.getMapper(EmpMapper.class);
emps = mapper.queryEmp();
for (Emp e :
emps) {
System.out.println(e);
}
}