Mybatis经常使用用法之 Mybatis缓存

这是我参与更文挑战的第2天,活动详情查看: 更文挑战web

一:定义

缓存就是内存中的数据,经常来自对数据库查询结果的保存,使用缓存,咱们能够避免频繁的与数据库 进行交互,进而提升响应速度redis

Mybatis也支持数据的缓存,分为一级缓存和二级缓存,能够经过下图理解一级缓存和二级缓存的做用范围:sql

image.png

以上能够看出数据库

  1. 一级缓存是sqlsession级别的缓存,直白的说就是单个sql语句的缓存,在操做数据库时,须要构建sqlsession对象,在对象中有一个数据结构(HashMap)用户存储缓存数据,不一样的sqlsession之间的缓存互不影响
  2. 二级缓存是Mapper级别的缓存,直白的说就是一个xml文件的缓存,该缓存默认是关闭的,多个sqlsession去操做同一个Mapper中的SQL语句,共用一个缓存,该缓存是跨sqlsession的

二:一级缓存

当咱们进行sql查询的时候,Mybatis会先到缓存中去查询该sql语句的缓存,若是该缓存已经存在,则直接返回缓存中的结果,再也不进行数据库交互,当缓存中不存在该sql语句的缓存的时候,则会直接去数据库查询,获取结果后,会将结果进行缓存,并同时发送给用户 当用户执行commit操做(插入,删除,更新),则会清空sqlsession的一级缓存,目的是为了不出现脏读。缓存

三:二级缓存

二级缓存和一级缓存原理同样,第一次查询会将数据放入缓存,后续查询会从缓存中取,可是一级缓存是sqlsession级别,二级缓存是mapper级别的,也就是说,多个sqlsession能够共享一个mapper中的二级缓存,若是两个mapper的namespace相同,即便是不一样文件的两个mapper,他们执行sql查询到的数据也维护在同一个二级缓存中。服务器

image.png

四:如何使用二级缓存

因为二级缓存默认是关闭的,因此须要咱们手动开启 1.首先,咱们须要在全局配置文件sqlMapConfig.xml文件中加入以下代码:markdown

<!--开启二级缓存--> 
<settings> <setting name="cacheEnabled" value="true"/> </settings>
复制代码

而后再具体的Mapper.xml中开启缓存,添加以下配置session

<cache></cache>
复制代码

咱们能够看到mapper.xml文件中就这么一个空标签,其实这里能够配置,PerpetualCache这个类是 mybatis默认实现缓存功能的类。咱们不写type就使用mybatis默认的缓存,也能够去实现Cache接口 来 自定义缓存。数据结构

开启了二级缓存后,还须要将要缓存的pojo实现Serializable接口,为了将缓存数据取出执行反序列化操 做,由于二级缓存数据存储介质多种多样,不必定只存在内存中,有可能存在硬盘中,若是咱们要再取 这个缓存的话,就须要反序列化了。因此mybatis中的pojo都去实现Serializable接口mybatis

mybatis中还能够配置userCacheflushCache等配置项,userCache是用来设置是否禁用二级缓 存 的,在statement中设置useCache=false能够禁用当前select语句的二级缓存,即每次查询都会发出 sql 去查询,默认状况是true,即该sql使用二级缓存

<select id="selectUserByUserId" useCache="false" resultType="com.pojo.User" parameterType="int"> 
    select * from user where id=#{id} 
</select>
复制代码

这种状况是针对每次查询都须要最新的数据sql,要设置成useCache=false,禁用二级缓存,直接从数 据 库中获取。 在mapper的同一个namespace中,若是有其它insert、update, delete操做数据后须要刷新缓存,如 果不执行刷新缓存会出现脏读。 设置statement配置中的flushCache="true”属性,默认状况下为true,即刷新缓存,若是改为false则 不 会刷新。使用缓存时若是手动修改数据库表中的查询数据会出现脏读。

<select id="selectUserByUserId" flushCache="true" useCache="false" resultType="com.pojo.User" parameterType="int"> 
    select * from user where id=#{id} 
</select>
复制代码

通常下执行完commit操做都须要刷新缓存,flushCache=true表示刷新缓存,这样能够避免数据库脏 读。因此咱们不用设置,默认便可

五:二级缓存整和redis

上面咱们介绍了 mybatis自带的二级缓存,可是这个缓存是单服务器工做,没法实现分布式缓存。 那么 什么是分布式缓存呢?通常分布式项目同一个服务都会部署多个,若是咱们用mybatis默认的缓存,用户第一次访问的时候根据负载均衡可能会访问到服务器A,当继续第二次访问的时候,可能就会访问到服务器B,那么原先在服务器A上的缓存,咱们是拿不到的,因此进行第二次访问的时候,仍是须要直接访问数据库,这样就违背了咱们用缓存存储的初衷,效果以下图所示:

image.png

为了解决这个问题,就得找一个分布式的缓存,专门用来存储缓存数据的,这样不一样的服务器要缓存数 据都往它那里存,取缓存数据也从它那里取,以下图所示:

image.png

如上图所示,在几个不一样的服务器之间,咱们使用第三方缓存框架,将缓存都放在这个第三方框架中, 然 后不管有多少台服务器,咱们都能从缓存中获取数据。 这里咱们介绍mybatis与redis的整合。

实现: pom文件:

<dependency> 
    <groupId>org.mybatis.caches</groupId> 
    <artifactId>mybatis-redis</artifactId> 
    <version>1.0.0-beta2</version> 
</dependency>
复制代码

配置文件:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.mapper.IUserMapper"> <cache type="org.mybatis.caches.redis.RedisCache" /> <select id="findAll" resultType="com.pojo.User" useCache="true"> select * from user </select> 复制代码

redis.properties:

redis.host=localhost 
redis.port=6379 
redis.connectionTimeout=5000 
redis.password= 
redis.database=0
复制代码

注意:这里的redis.properties为固定文件名称,不可变

为何要名称固定为这个呢?接下来咱们翻阅一下源码,找寻一下答案.

RedisCache和你们广泛实现Mybatis的缓存方案大同小异,无非是实现Cache接口,并使用jedis操做缓 存;

image.png

RedisCache在mybatis启动的时候,由MyBatis的CacheBuilder建立,建立的方式很简单,就是调用 RedisCache的带有String参数的构造方法,即RedisCache(String id);而在RedisCache的构造方法中, 调用了 RedisConfigu rationBuilder 来建立 RedisConfig 对象,并使用 RedisConfig 来建立JedisPool。 接下来咱们进入 parseConfiguration()方法中继续分析。

image.png 咱们能够看到 在该方法的第一行就更加一个路径,调用getResourceAsStream()方法,将文件加载为IO流, 显而易见,咱们的配置文件路径确定就是代码中对应的redisPropertiesFilename属性

咱们在看一下redisPropertiesFilename属性对应的是什么值

image.png 咱们看到 实际redisPropertiesFilename并无指定什么值,再往下看,咱们看到一个构造函数,在该构造函数中,咱们发现,redisPropertiesFilename其实就是上面常量中所对应的值,而常量对应的值就是咱们的 redis.properties,由此能够得出上面的结论。

本篇文章到此结束,但愿对各位小伙伴有所帮助

相关文章
相关标签/搜索