解读Mybatis缓存机制

缓存及缓存机制

 传统的关系型数据库,十分强调数据的一致性,并为此降低读写性能付出了巨大的代价,虽然关系型数据库存储数据和处理数据的可靠性很不错,但一旦面对海量数据的处理的时候效率就会变得很差,特别是遇到高并发读写的时候性能就会下降的非常厉害。比如这样一个场景:使用sql语句(select * from user where id =1;)查询了数据库中id为1的数据,此时数据库会进行查询操作,并返回一个User类型的数据,没有进行增删改的操作,然后再次使用sql语句查询数据库,程序会重复上面的步骤.在这种频繁的查询操作下,对数据库来说是一个巨大的挑战.
 所以我们引入了缓存(cache),将经常不被修改并且频繁查询的数据放入内存中,减少对数据库的频繁读写操作,降低数据库的压力.当要读取数据时,会首先从内存中查找需要的数据,如果找到了则直接执行,找不到的话则从数据库中找。由于内存的运行速度比从数据库中查询快得多,故缓存的作用就是帮助查询更快地运行。

Mysql缓存机制就是缓存sql 文本及缓存结果,用KV形式(是一种以键值对存储数据的一种形式,可以理解为一个大的map,每个键都会对应一个唯一的值。)保存再服务器内存中,如果运行相同的sql,服务器直接从缓存中去获取结果,不需要在再去解析、优化、执行sql。 如果这个表修改了,那么使用这个表中的所有缓存将不再有效,查询缓存值得相关条目将被清空。
 对于频繁更新的表,查询缓存不合适,对于一些不变的数据且有大量相同sql查询的表,查询缓存会节省很大的性能。

Mybatis缓存机制

 和大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持;
 一级缓存是Mybatis默认开启的,是基于 PerpetualCache 的 HashMap 本地缓存,存储作用域为 Session,当 Session flush (会话刷新)或 close 之后,该Session中的所有 Cache 就将清空。
 二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache、Hazelcast等。

一级缓存

 在应用运行过程中,我们有可能在一次数据库会话中,执行多次查询条件完全相同的SQL,MyBatis提供了一级缓存的方案优化这部分场景,如果是相同的SQL语句,会优先命中一级缓存,避免直接对数据库进行查询,提高性能。具体执行过程如下图所示。

一级缓存

 每个SqlSession中持有了Executor(执行器),每个Executor中有一个LocalCache(本地缓存)。当用户发起查询时,MyBatis根据当前执行的语句生成MappedStatement(在MyBatis启动时,会解析这些包含SQL的XML文件,并将其包装成为MapperStatement对象,并将MapperStatement注册到全局的configuration对象上),在Local Cache进行查询,如果缓存命中的话,直接返回结果给用户,如果缓存没有命中的话,查询数据库,结果写入Local Cache,最后返回结果给用户。具体实现类的类关系图如下图所示。

一级缓存 具体实现类的类关系图

代码流程

  1. 第一次执行select完毕会将查到的数据写入SqlSession内的HashMap中缓存起来
  2. 第二次执行select会从缓存中查数据,如果select相同切传参数一样,那么就能从缓存中返回数据,不用去数据库了,从而提高了效率

注意事项:

  • 如果SqlSession执行了DML操作(insert、update、delete),并commit了,那么mybatis就会清空当前SqlSession缓存中的所有缓存数据,这样可以保证缓存中的存的数据永远和数据库中一致,避免出现脏读
  • 当一个SqlSession结束后那么他里面的一级缓存也就不存在了,mybatis默认是开启一级缓存,不需要配置

一级缓存的开启与关闭

  • 一级缓存默认开启
  • 关闭一级缓存需要在mybatis配置文件的settings标签设置
<setting name="localCacheScope" value="SESSION"/>

导致一级缓存不命中的原因

  • 一级缓存关闭;
  • 一级缓存开启,但是使用了不同的SqlSession进行查询;
  • 使用相同的SqlSession,但是查询条件发生了变化;
  • 使用了相同的查询条件,但是两次查询之间SqlSession执行了commit、clearCache或close(关闭之后查询会报错)操作;
  • 使用了相同的查询条件,但是两次查询之间SqlSession执行了insert、update或delete操作,此时无论三种标签的
    flushCache 属性是否为 false,都会清空 sqlSession的缓存;
  • select标签的flushCache属性为true

清空一级缓存的操作

  • SqlSession调用commit方法;
  • SqlSession调用clearCache方法;
  • select标签的flushCache属性为true;

SqlSession执行了insert、update或delete操作,此时无论三种标签的flushCache属性是否为 false;

一级缓存实验

实验1
 开启一级缓存,范围为会话级别,调用三次Getbyid
代码如下所示:

public static void main(String[] args) throws IOException {
   
	}
	SqlSession ss;
	Userdao udao;
	//定义一个解析工具
	@Before
	public void  setup() throws IOException {
   
		
		String resource = "MybatisConfig.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
		ss = sqlSessionFactory.openSession();
		udao=ss.getMapper(Userdao.class);

	}
	@Test
	public void Getbyid() {
   
		System.out.println(udao.Getbyid1(1));
		System.out.println(udao.Getbyid1(1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值