Mybatis中给我们提供了缓存,其中有一级缓存和二级缓存
缓存是用来干嘛的?
- 当我们使用查询语句到数据库查询,每一次查询都会去访问数据库,频繁的访问数据库就会有压力,缓存就是来缓解数据库压力的,提升系统的性能
一级缓存
一级缓存Mybatis自己是默认开启的,是不需要我们去管的,不过一级缓存是
SqlSession级别的,在操作数据库的时候我们需要创建SqlSession对象,
SqlSession自己有个结构是HashMap的缓存区,每一个SqlSession都有
自己的缓存区.
下面作个实验
代码:
public void cacheTest()throws Exception{
// 读取mybatis核心配置文件
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
// 创建SqlSession的创建
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
// 获取SqlSession
SqlSession session = factory.openSession();
// 获取EmpMapper
EmpMapper mapper = session.getMapper(EmpMapper.class);
// 根据id查询
Emp emp1 = mapper.findEmpById(2);
System.out.println(emp1);
System.out.println("----------分割线----------");
// 根据id再次进行相同的查询
Emp emp2 = mapper.findEmpById(2);
System.out.println(emp2);
// 关闭资源
session.close();
is.close();
}
日志信息
2021-04-03 15:03:04,307 572 [ main] DEBUG m.mapper.EmpMapper.findEmpById - ==> Preparing: select * from emp where id=?
2021-04-03 15:03:04,339 604 [ main] DEBUG m.mapper.EmpMapper.findEmpById - ==> Parameters: 2(Integer)
2021-04-03 15:03:04,360 625 [ main] DEBUG m.mapper.EmpMapper.findEmpById - <== Total: 1
Emp{ id=2, name='小赵', age=21, deptId=0}
----------分割线----------
2021-04-03 15:03:04,372 637 [ main] DEBUG com.ssm.mapper.EmpMapper - Cache Hit Ratio [com.ssm.mapper.EmpMapper]: 0.0
Emp{ id=2, name='小赵', age=21, deptId=0}
使用同一个SqlSession进行了两次一样的查询,可以从日志信息中看到第一次查询的时候显示发送了sql语句,而第二次查询则没有显示发送sql语句,说明是从缓存中获取的数据,而不是数据库
什么时候清空一级缓存?
当我们执行添加,修改,删除操作的时候mybatis会自动清空一级缓存,准确的来说是我们执行commit()事务提交的时候清空
实验
代码:
public void cacheTest2()throws Exception{
// 读取mybatis核心配置文件
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
// 创建SqlSession的创建
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
// 获取SqlSession
SqlSession session = factory.openSession();
// 获取EmpMapper
EmpMapper mapper = session.getMapper(EmpMapper.class);
// 根据id查询
Emp emp1 = mapper.findEmpById(2);
System.out.println(emp1);
System.out.println("----------分割线----------");
// 删除id为4的员工
mapper.delEmpById(4);
session.commit();
System.out.println("----------分割线----------");
// 根据id再次进行相同的查询
Emp emp2 = mapper.findEmpById(2);
System.out.println(emp2);
// 关闭资源
session.close();
is.close();
}
日志信息
2021-04-03 15:12:53,322 483 [ main] DEBUG m.mapper.EmpMapper.findEmpById - ==> Preparing: select * from emp where id=?
2021-04-03 15:12:53,348 509 [ main] DEBUG m.mapper.EmpMapper.findEmpById - ==> Parameters: 2(Integer)
2021-04-03 15:12:53,377 538 [ main] DEBUG m.mapper.EmpMapper.findEmpById - <== Total: 1
Emp{ id=2, name='小赵', age=21, deptId=0}
----------分割线----------
2021-04-03 15:12:53,385 546 [ main] DEBUG sm.mapper.EmpMapper.delEmpById - ==> Preparing: delete from emp where id=?
2021-04-03 15:12:53,385 546 [ main] DEBUG sm.mapper.EmpMapper.delEmpById - ==> Parameters: 4(Integer)
2021-04-03 15:12:53,415 576 [ main] DEBUG sm.mapper.EmpMapper.delEmpById - <== Updates: 1
2021-04-03 15:12:53,415 576 [ main] DEBUG ansaction.jdbc.JdbcTransaction - Committing JDBC Connection [com.mysql.jdbc.JDBC4Connection@43015c69]
----------分割线----------
2021-04-03 15:12:53,428 589 [ main] DEBUG com.ssm.mapper.EmpMapper - Cache Hit Ratio [com.ssm.mapper.EmpMapper]: 0.0
2021-04-03 15:12:53,428 589 [ main] DEBUG m.mapper.EmpMapper.findEmpById - ==> Preparing: select * from emp where id=?
2021-04-03 15:12:53,428 589 [ main] DEBUG m.mapper.EmpMapper.findEmpById - ==> Parameters: 2(Integer)
2021-04-03 15:12:53,430 591 [ main] DEBUG m.mapper.EmpMapper.findEmpById - <== Total: 1
Emp{ id=2, name='小赵', age=21, deptId=0}
这一次我们在执行第二次查询的之前执行了一次删除的操作,可以看到打印出来的日志信息中出现了3条sql语句,第一条是根据id查询,第二条是根据id删除,第三条又是根据id查询的,这次第二次查询的操作是去数据库中查询的,而不是从缓存中获取的,说明缓存中没有相同的数据
二级缓存
二级缓存是Mapper级别的,一个Mapper有着一个缓存区,就是说不管几个
SqlSession只要他们获取的是同一个Mapper,缓存数据就会是共享的,不过
二级缓存需要我们自己去开启
开启二级缓存
- 第一步:
先到mybatis的核心配置文件中配置
<settings>
<!--开启mybatis二级缓存-->
<setting name="cacheEnabled" value="true"></setting>
</settings>
- 第二步
开启二级缓存的分开关
接口开启方法:使用@CacheNamespace注解
//通过注解开启二级缓存的分开关
@CacheNamespace
public interface EmpMapper {
在xml中开启方法:添加"cache"标签
<mapper namespace="com.ssm.mapper.EmpMapper">
<!--xml中二级缓存分开关-->
<cache></cache>
注意:
xml和接口中只要其中一个开启就可以了,不然会报以下的异常
Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: java.lang.IllegalArgumentException: Caches collection already contains value for com.ssm.mapper.EmpMapper
- 第三步
让Mapper对应的实例类实现Serializable接口
//使用mybatis二级缓存的实体类必须实现Serializable接口
public class Emp implements Serializable{
完成配置以后来做个实验
代码:
public void secondLevelCacheTest(){
// 第一个SqlSession
SqlSession session = MybatisUtil.getSession();
EmpMapper mapper = session.getMapper(EmpMapper.class);
Emp e = mapper.findEmpById(2);
System.out.println(e);
session.close();
System.out.println("----------分割线----------");
// 第二个SqlSession
SqlSession session2 = MybatisUtil.getSession();
EmpMapper mapper2 = session2.getMapper(EmpMapper.class);
Emp e2 = mapper2.findEmpById(2);
System.out.println(e2);
session2.close();
System.out.println("-----------分割线------------");
// 第三个SqlSession
SqlSession session3 = MybatisUtil.getSession();
EmpMapper mapper3 = session3.getMapper(EmpMapper.class);
Emp e3 = mapper3.findEmpById(2);
System.out.println(e3);
session3.close();
}
日志信息
2021-04-03 15:44:46,137 582 [ main] DEBUG m.mapper.EmpMapper.findEmpById - ==> Preparing: select * from emp where id=?
2021-04-03 15:44:46,163 608 [ main] DEBUG m.mapper.EmpMapper.findEmpById - ==> Parameters: 2(Integer)
2021-04-03 15:44:46,183 628 [ main] DEBUG m.mapper.EmpMapper.findEmpById - <== Total: 1
Emp{ id=2, name='小赵', age=21, deptId=0}
2021-04-03 15:44:46,197 642 [ main] DEBUG ansaction.jdbc.JdbcTransaction - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@3eb91815]
2021-04-03 15:44:46,198 643 [ main] DEBUG ansaction.jdbc.JdbcTransaction - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@3eb91815]
2021-04-03 15:44:46,198 643 [ main] DEBUG source.pooled.PooledDataSource - Returned connection 1052317717 to pool.
----------分割线----------
2021-04-03 15:44:46,201 646 [ main] DEBUG com.ssm.mapper.EmpMapper - Cache Hit Ratio [com.ssm.mapper.EmpMapper]: 0.5
Emp{ id=2, name='小赵', age=21, deptId=0}
-----------分割线------------
2021-04-03 15:44:46,201 646 [ main] DEBUG com.ssm.mapper.EmpMapper - Cache Hit Ratio [com.ssm.mapper.EmpMapper]: 0.6666666666666666
Emp{ id=2, name='小赵', age=21, deptId=0}
这次是三次相同的查询,不同的SqlSession,获取的同一个Mapper,只有第一次查询的时候日志显示向数据库发送了sql语句,其他两次都没有发送sql语句,说明其他两次都是从缓存中获取的数据.
(03/04/2021)