首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

杂谈——Mybatis一二级缓存简单详解

先说缓存,合理使用缓存是优化中最常见。将从数据库中查询出来的数据放入缓存(内存)中,每次查询数据时,先判断缓存区中是否存在数据,如果存在,就从缓存区中获取数据,如果不存在,就从数据库中获取数据,将数据存放到缓存区中。这样的话,下次访问该数据的时候使就不必从数据库查询,而是直接从缓存中读取,避免频繁操作数据库,提高数据访问效率,减轻数据库的压力,同时提高系统性能。

咱们今天就来认识一下Mybatis的一二级缓存。

1.一级缓存

一级缓存是SqlSession级别的缓存,Mybatis默认开启一级缓存。在操作数据库时需要构造sqlSession对象,在该对象中有一个数据结构用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。换句话说,不同的sqlSession中的缓存是互相不能读取的,即不共享。

一级缓存的工作原理如下图:

流程描述如下:

1.用户发起查询请求,查找某条数据,sqlSession先去缓存中查找,是否有该数据,如果有,读取;

2.如果没有,从数据库中查询,并将查询到的数据放入一级缓存区域,供下次查找使用。

需要注意,sqlSession执行commit,即增删改操作时会清空缓存。这么做的目的是避免脏读。

为什么说清空缓存就可以避免脏读呢?

如果commit不清空缓存,会有以下场景:

A查询了某商品库存为10件,并将10件库存的数据存入缓存中,之后被客户买走了10件,数据被delete了,但是下次查询这件商品时,并不从数据库中查询,而是从缓存中查询,就会出现错误。

既然有了一级缓存,那么为什么要提供二级缓存呢?是一级缓存不够骚了吗?

是的,它的确不够骚。

首先,因为它不能共享缓存区;其次,实际开发中,MyBatis通常和Spring进行整合开发。Spring将事务放到Service中管理,对于每一个service中的sqlsession是不同的,这是通过mybatis-spring中的org.mybatis.spring.mapper.MapperScannerConfigurer创建sqlsession自动注入到service中的。 每次查询之后都要进行关闭sqlSession,关闭之后数据被清空。所以spring整合之后,如果没有事务,一级缓存是没有意义的。

那二级缓存就更加好了吗?下面来看看。

2.二级缓存

二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,也就是说,二级缓存是跨SqlSession的,因此二级缓存的作用范围更大。上文说到,二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。

UserMapper有一个二级缓存区域(按namespace分),其它mapper也有自己的二级缓存区域(按namespace分)。每一个namespace的mapper都有一个二级缓存区域,两个mapper的namespace如果相同,这两个mapper执行sql查询到数据将存在相同的二级缓存区域中。

二级缓存原理如下图:

Mybatis的二级缓存是默认关闭的,那么如何开启二级缓存呢?且看如下步骤:

开启二级缓存:

1,打开总开关,在MyBatis的配置文件中加入:

2,在需要开启二级缓存的mapper.xml中加入caceh标签

3,让使用二级缓存的POJO类实现Serializable接口

测试一下

输出结果:

我们可以从打印的信息看出,两个sqlSession,去查询同一条数据,只会发起一次select查询语句,第二次直接从Cache中读取。

前面我们说到,Spring和MyBatis整合时, 每次查询之后都要进行关闭sqlSession,关闭之后数据被清空。所以spring整合之后,如果没有事务,一级缓存是没有意义的。而如果开启二级缓存的话,关闭sqlsession后,会把该sqlsession一级缓存中的数据添加到namespace的二级缓存中。这样,缓存在sqlsession关闭之后依然存在。

总结:

对于查询多commit少且用户对查询结果实时性要求不高,此时采用mybatis二级缓存技术可以降低数据库访问量,提高访问速度。

但不能滥用二级缓存,二级缓存也有很多弊端,从MyBatis默认二级缓存是关闭的就可以看出来。为什么说它有弊端呢?

二级缓存是建立在同一个namespace下的,如果对表的操作查询可能有多个namespace,那么得到的数据就是错误的。

举个简单的例子:

订单和订单详情,orderMapper、orderDetailMapper。在查询订单详情时我们需要把订单信息也查询出来,那么这个订单详情的信息被二级缓存在orderDetailMapper的namespace中,这个时候有人要修改订单的基本信息,那就是在orderMapper的namespace下修改,他是不会影响到orderDetailMapper的缓存的,那么你再次查找订单详情时,拿到的是缓存的数据,这个数据其实已经是过时的。

根据以上,想要使用二级缓存时需要想好两个问题:

对该表的操作与查询都在同一个namespace下,其他的namespace如果有操作,就会发生数据的脏读。

对关联表的查询,关联的所有表的操作都必须在同一个namespace。

好啦,以上就是关于Mybatis一二级缓存的相关知识总结

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181224G0TQ7K00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券