一级缓存
/*
MyBatis实现类 PerpetualCache 根据map进行存储的 hashcode+sqlid+sql+hashcode+envenments...
* 一级缓存
* 1、默认开启
* 2、作用于基于sqlSession
* 失效情况:
* 1、不同的sqlSession会使一级缓存失效
* 2、setting localCacheScope SESSION
* STAEMENT 相当于关闭一级缓存
* 3、同一个查询 查询条件不一样
* 4、同样的查询 中间执行了增删改查
* 5、手动清除缓存 sqlSession.clearCache();
*
* */
@Test
public void Test01(){
DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
Dept22 dept22 = new Dept22();
dept22.setId(1);
List<Dept22> depts0 =mapper.selectDept(dept22);
System.out.println(depts0);
EmpMapper mapper1 = sqlSession.getMapper(EmpMapper.class);
// Emp emp = new Emp();
// emp.setUsername("好好");
// emp.setCreate_date(LocalDate.now());
// emp.setDept_id(1);
// mapper1.insertEmp(emp);
List<Dept22> depts = mapper.selectDept(dept22);
System.out.println(depts);
sqlSession.commit();
}
二级缓存
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kdy.mapper.DeptMapper">
<cache-ref namespace="com.kdy.mapper.EmpMapper"/>
<cache></cache>
<select id="selectDept" resultType="com.kdy.pojo.Dept22" useCache="false" >
select * from dept
<where>
<if test="id!=null and id!=''">
and id = #{id}
</if>
<if test="dept_name!=null and dept_name!=''">
and dept_name= #{dept_name}
</if>
</where>
</select>
<insert id="insertDept" flushCache="false">
insert into dept(dept_name) values(#{dept_name})
</insert>
</mapper>
/**
* 二级缓存
* 1、默认也是开启 没有实现
* 2、作用域 基于全局范围 应用级别
* 不通的SQLSESSION 共享缓存
* 3、缓存默认实现也是PerpetualCache 但是二级缓存 根据不同的mapper命名空间多饱了一层
*
* 实现
*
* 1、开启二级缓存 mybatis config 文件中 <setting name="cacheEnabled" value="true"></setting> 默认就是开启的,增加可读性
* 2、mapper映射文件配置 在需要用到二级缓存的映射文件中加入 <cache></cache> 基于Mapper映射文件实现缓存的 基于Mapper映射文件的命名空间来进行存储的
* ( Configuation 文件中 protected final Map<String, Cache> caches = new StrictMap<>("Caches collection"); 是存储二级缓存的
* key:mapper namespace value: PerpetualCache里面的Mapper
* )
* 3、在需要使用到的二级缓存javaBean中实现序列化接口 implements Serializable
* 命名空间
*
* 4、sqlSession.commit执行后 缓存生效
*
*
* - Cache Hit Ratio [com.kdy.mapper.DeptMapper]: xxx 缓存命中率 1/(1-xxx) = 查询总次数
*
*
* 缓存顺序:
* 一级缓存在查询完就行存储
* 二级缓存是在事务提交或关闭的时候存储
*
*先在二级缓存中查,没有查到再去一级缓存
* PerpetualCache中 id 命名空间是二级缓存 LocalCache是一级缓存
*
*
* 二级缓存失效:
* 1、 同一个命名空间执行了 增删改 并提交
* 当Mapper中 增删改标签 添加 flushCache="false" 缓存不会清空 但是要慎重脏读问题
* 除非保证查询数据不会增删改
*
* 2、 让查询的数据不存储到缓存中
* select useCache="false"
*
* 3、执行增删改 清除关联缓存
* <cache-ref namespace="com.kdy.mapper.DeptMapper"/>
*
*
*
* **/
@Test
public void cache02() throws IOException {
String mybatisconfig = "mybatis.config.xml";
InputStream inputStream = Resources.getResourceAsStream(mybatisconfig);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
DeptMapper mapper = sqlSession1.getMapper(DeptMapper.class);
DeptMapper mapper1 = sqlSession2.getMapper(DeptMapper.class);
Dept22 dept22 = new Dept22();
dept22.setId(1);
List<Dept22> dept2222 =mapper.selectDept(dept22);
sqlSession1.commit();
System.out.println(dept2222);
EmpMapper mapper2 = sqlSession1.getMapper(EmpMapper.class);
// Emp emp = new Emp();
// emp.setUsername("kongjkong");
// emp.setCreate_date(LocalDate.of(2022,2,2));
// emp.setDept_id(1);
// mapper2.insertEmp(emp);
List<Dept22> dept333 =mapper.selectDept(dept22);
sqlSession1.commit();
System.out.println(dept333);
// sqlSession1.commit();
// EmpMapper mapper2 = sqlSession1.getMapper(EmpMapper.class);
// Emp emp = new Emp();
// emp.setUsername("孔德阳");
// mapper2.insertEmp(emp);
// mapper1.insertDept("nihao");
// sqlSession2.commit();
// dept2222 =mapper.selectDept(dept22);
// dept2222 = mapper1.selectDept(dept22);
// sqlSession2.commit();
// System.out.println(1111);
}
cache标签配置
<!--
eviction 当缓存达到size 设定的数量时 以那种方式进行 回收缓存
LRU – 最近最少使用:移除最长时间不被使用的对象。( 默认 )
FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。
flushInterval 刷新时间 单位 毫秒
size 可以缓存的数量 map key的数量
readOnly true 缓存的数据性能更高 数据是指向地址的 sqlsession 提交后 改变值会造成脏读
true后 是引用值
false 默认 读取 缓存的数据性能更低 复制数据 sqlsession 提交后 改变值不会造成脏读
false后 是复制值
type="" org.apache.ibatis.cache.impl.PerpetualCache
指定第三方缓存 实现 Cache接口
-->
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="false"
></cache>
//readOnly true 脏读演示
@Test
public void cache03() throws IOException {
String mybatisconfig = "mybatis.config.xml";
InputStream inputStream = Resources.getResourceAsStream(mybatisconfig);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
DeptMapper mapper = sqlSession1.getMapper(DeptMapper.class);
DeptMapper mapper1 = sqlSession2.getMapper(DeptMapper.class);
Dept22 dept22 = new Dept22();
dept22.setId(1);
List<Dept22> dept22s = mapper1.selectDept(dept22);
System.out.println(dept22s);
sqlSession2.commit();
dept22s.get(0).setDept_name("新经理");
List<Dept22> dept223 = mapper1.selectDept(dept22);
System.out.println(dept223);
}
第三方缓存
为什么使用第三方缓存
Mybastis JVM内存空间中,缓存过多会造成内存溢出。
常用的缓存中间件
Memcached Redis 缓存中间件 ehcache 不需要配置 相对简单
MyBatis 与 Redis 简单整合使用
redis支持 string hash list hashset
更简单实现复杂的业务
还可以实现 分布式下面的分布式锁 分布式session MQ使用等
1、下载win版本redis codeload.github.com/cinience/Re…
① 设置密码 redis.windows.conf requirepass 123456
② 运行 redis-server.exe redis.windows.conf
③ 启动 redis-cli.exe 启动客户端 输入 auth 123456
set str helloword
get str
2、安装mybatis redis 依赖
github地址 :github.com/mybatis/red…
文档地址 : mybatis.org/redis-cache…
① 添加依赖
<!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-redis -->
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-redis</artifactId>
<version>1.0.0-beta2</version>
</dependency>
② Mapper xml中加入cache type
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="false"
type="org.mybatis.caches.redis.RedisCache"
></cache>
③ 加入redis 配置文件
host=localhost
port=6379
connectionTimeout=5000
soTimeout=5000
password=
database=0
注: 可以在mybatis redis 仓库中找示例找到源码 并把redis.去掉
3、验证
下载 github.com/cinience/Re… 的客户端