Mybatis中的缓存管理

目录

  • Mybatis中的缓存管理
  • 查询缓存工作原理:
  • 配置缓存:
    • 默认配置:
    • 使用二级缓存:
    • 刷新缓存过程:
  • 配置EHcache
  • 产生脏数据
  • 使用原则:

Mybatis中的缓存管理

查询缓存工作原理:

查询语句?<--->?缓存?<---->?DB

缓存内容:

Mybatis中存放的是查询的内容;

缓存对比:

类别 作用范围 生命周期
一级缓存 namespace 和sqlsession的生存周期相同
二级缓存 namespace 和整个应用的生命周期相同

一级缓存:默认是开启的,无开关关闭;

二级缓存:默认是开启的,需要手动关闭,二级缓存可以外置第三方的产品。

配置缓存:

默认配置:

  • 一级缓存默认是开启的,无需配置,也不能关闭;
  • 二级缓存也是默认开启状态的,如果想要关闭的话在“全局配置文件”中配置;全局关闭之后后面的配置也就不起作用了;
<configuration>
    <!--二级缓存的全局开关-->
    <settings>
        <setting name="cacheEnabled" value="false"/>
    </settings>
</configuration>

局部关闭设置:

<!--在查询语句里添加设置:useCache="false"-->
<select id="selectStudentById2" resultType="Student" useCache="false">
    select id,name,age,score from student where id=#{xx}
</select>

开启内置二级缓存:

  1. 在mapper文件中添加并配置标签:

    <cache size="512" eviction="LRU" flushInterval="100000"/>
    • flushInterval:刷新间隔;单位是ms;
    • eviction:收回缓存的策略;LRU为默认值,移除最长时间不被使用的对象;
    • size:可以存储集合或者对象的引用数目;
    • readOnly:设置只读,默认值为false;

    为什么配置在mapper文件中:由于Mybatis的二级缓存是和命名空间绑定的(作用范围),所以二级缓存需要配置在Mapper.xml 映射文件中或者在接口文件中(注解形式配置);

  2. 操作的实体类实现Serializable接口。

使用二级缓存:

证明二级缓存Demo

public void Test01() throws IOException {
    SqlSession session = MyBatisUtil.getSqlSession();
    studentDao = session.getMapper(IStudentDao.class);
    //第一次查询
    Student student = studentDao.selectStudentById(2);
    System.out.println("第一次查询:"+student);
    //关闭一级缓存
    session.close();

    SqlSession session2 = MyBatisUtil.getSqlSession();
    studentDao = session2.getMapper(IStudentDao.class);
    //第二次查询
    Student student2 = studentDao.selectStudentById(2);
    System.out.println("第二次查询:"+student2);
    //关闭一级缓存
    session2.close();

    SqlSession session3 = MyBatisUtil.getSqlSession();
    studentDao = session3.getMapper(IStudentDao.class);
    //第三次查询
    Student student3 = studentDao.selectStudentById(2);
    System.out.println("第三次查询:"+student3);
    //关闭一级缓存
    session3.close();
}

输出日志文件:

[DEBUG] Cache Hit Ratio [com.abc.dao.IStudentDao]: 0.0 [DEBUG] Cache Hit Ratio [com.abc.dao.IStudentDao]: 0.0 [DEBUG] ==> Preparing: select id,name,age,score from student where id=? [DEBUG] ==> Parameters: 2(Integer) [DEBUG] <== Total: 1 第一次查询:Student{id=2, name=‘李四‘, age=18, score=90.0} [DEBUG] Cache Hit Ratio [com.abc.dao.IStudentDao]: 0.5 第二次查询:Student{id=2, name=‘李四‘, age=18, score=90.0} [DEBUG] Cache Hit Ratio [com.abc.dao.IStudentDao]: 0.6666666666666666 第三次查询:Student{id=2, name=‘李四‘, age=18, score=90.0}

可以看到第一次查询访问DB,关闭了sqlsession之后一级缓存已经无效,但是第二次和第三次查询都成功命中了缓存;

过程:在一级缓存的sqlsession关闭之后,sqlsession就会把数据保存到二级缓存中,在这之后二级缓存就有了缓存数据;

刷新缓存Demo:

public void Test02() throws IOException {
    SqlSession session = MyBatisUtil.getSqlSession();
    studentDao = session.getMapper(IStudentDao.class);
    //第一次查询
    Student student = studentDao.selectStudentById(2);
    System.out.println("第一次查询:"+student);
    //关闭一级缓存
    session.close();

    SqlSession session2 = MyBatisUtil.getSqlSession();
    studentDao = session2.getMapper(IStudentDao.class);
    //执行增删改操作
    studentDao.insertStudent(new Student("小吕",21,96));

    //第二次查询
    Student student2 = studentDao.selectStudentById(2);
    System.out.println("第二次查询:"+student2);
    //关闭一级缓存
    session2.close();
}

日志文件:

[DEBUG] Cache Hit Ratio [com.abc.dao.IStudentDao]: 0.0 [DEBUG] ==> Preparing: select id,name,age,score from student where id=? [DEBUG] ==> Parameters: 2(Integer) [DEBUG] <== Total: 1 第一次查询:Student{id=2, name=‘李四‘, age=18, score=90.0} [DEBUG] ==> Preparing: insert into student (name,age,score) value (?,?,?) [DEBUG] ==> Parameters: 小吕(String), 21(Integer), 96.0(Double) [DEBUG] <== Updates: 1 [DEBUG] Cache Hit Ratio [com.abc.dao.IStudentDao]: 0.5 [DEBUG] ==> Preparing: select id,name,age,score from student where id=? [DEBUG] ==> Parameters: 2(Integer) [DEBUG] <== Total: 1 第二次查询:Student{id=2, name=‘李四‘, age=18, score=90.0}

第一次查询之后关闭sqlsession并进行了插入操作,然后再次查询时候依然访问DB,因为缓存被刷新了;

刷新缓存过程:

Mybatis缓存底部实现:

一级缓存和二级缓存的底层都是通过map来实现的

  • 对应key : HashCode + statementId + SQL语句(对象的哈希值+mapper文件中执行SQL语句的标签的id+SQL语句)
  • 对应value : 查询结果本身

缓存刷新

  • 增删改操作会刷新一级缓存和二级缓存:刷新缓存实际上是将缓存中所有的Entry对象的value置为null。并未删除整个Entry对象,key仍保留;所以当发生刷新之后再次查询会显示本次命中缓存,但是却到DB中查询;
  • 增删改默认影响二级缓存的,但也可以让其不影响:只需要在对应增删改的statement中添加flushCache="false"
    <insert id="insertStudent" flushCache="false">
        insert into student (name,age,score) value (#{name},#{age},#{score})
    </insert>

所以综上,有两种情况是直接到DB中执行真正的查询:

  1. Map中根本不存在要查找的Entry,即没有要查找的key
  2. Map中存在要查找的key,但是它的value值为null

配置EHcache

EHcache是外置的二级缓存,Mybatis官方也提供了EHcache的缓存:https://github.com/mybatis/ehcache-cache>

配置:

  1. 首先导入两个jar:EHcache核心jar包,Mybatis和EHcache整合jar
<!-- https://mvnrepository.com/artifact/org.ehcache/ehcache -->
<dependency>
  <groupId>org.ehcache</groupId>
  <artifactId>ehcache</artifactId>
  <version>3.8.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-ehcache -->
<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis-ehcache</artifactId>
  <version>1.0.0</version>
</dependency>
  1. 在映射文件中添加:

    <cache type="org.mybatis.caches.ehcache.EhcacheCache">
        <property name="maxElementsInMemory" value="1000"/>
    </cache>

    其中中可以添加属性和它对应的值;

产生脏数据

脏数据产生:在关系型数据库中,经常使用多表联合查询,需要关联多个数据表才能得到查询结果,查询结果会被放在一个namespace的缓存中;涉及到其他表的增删改通常不在一个映射文件中,当其他的表的信息变更的时候,在当前的namespace缓存中查到的信息还是没有改变之前的数据。

避免脏数据的出现:这时需要用到参照缓存。当某几个表可以作为一个业务整体时,通常是让几个会关联的ER 表同时使用同一个二级缓存;当参照缓存更改之后就会重新到DB中查询;

<mapper namespace= "UserMapper" >
    <cache-ref namespace= "RoleMapper" />
</mapper>

使用原则:

  1. 不能出现多个namespace操作一张表的情况。

    原因:二级缓存的作用范围只是单个namespace。

  2. 使用单表查询为主,尽量避免关联数据被改变;
    对于关联查询的数据表不要出现增删改等操作,容易出现脏数据。
  3. 查询操作较多,增删改较少的应用;

原文地址:https://www.cnblogs.com/gbetter/p/11792974.html

时间: 2024-08-10 20:17:44

Mybatis中的缓存管理的相关文章

SSM-MyBatis-17:Mybatis中二级缓存

------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 二级缓存 Mybatis中,默认二级缓存是开启的.可以关闭. 一级缓存开启的.可以被卸载吗?不可以的.一级缓存不可以卸载,天然和框架绑定.内置二级缓存 由于MyBatis从缓存中读取数据的依据与SQL的id相关,而非查询出的对象.所以,使用二级缓存的目的,不是在多个查询间共享查询结果(所有查询中只要查询结果中存在该对象, 就直接从缓存中读取,这是对查询结果的共享,Hibernate中的缓存就是为了在多个查询

一次读懂mybatis中的缓存机制

缓存功能针对于查询(没听说果UPDATE,INSERT语句要缓存什么,都是直接执行的) 默认情况下,mybatis会启用一级缓存. 如果使用同一个session对象调用了相同的SELECT语句,则直接会从缓存中返回结果,而不是再查询一次数据库. 注意:session调用commit或close方法后,这个session中的一级缓存就会被清空 例如: 根据日志输出可以看出,下面代码只会发出一条sql查询语句 SqlSession sqlSession = MyBatisSqlSessionFact

【MyBatis学习13】MyBatis中的二级缓存

1. 二级缓存的原理 前面介绍了,mybatis中的二级缓存是mapper级别的缓存,值得注意的是,不同的mapper都有一个二级缓存,也就是说,不同的mapper之间的二级缓存是互不影响的.为了更加清楚的描述二级缓存,先来看一个示意图: 从图中可以看出: sqlSession1去查询用户id为1的用户信息,查询到用户信息会将查询数据存储到该UserMapper的二级缓存中. 如果SqlSession3去执行相同 mapper下sql,执行commit提交,则会清空该UserMapper下二级缓

MyBatis中关于session以及cache的管理

Mybatis中缓存分为一级缓存与二级缓存: 一级缓存指的只是缓存级别的一个命名,主要就是每个sqlsession里都有一个HashMap来存储数据,当然不同对象每个缓存区域也不一样,所以一级缓存是不相互影响的. 二级缓存是mapper级别的的,也就是每个sqlsession都可以访问同一个mapper,这里不是说二级缓存只有一个,也是每个mapper中有一个,就比如UserMapper,TestMapper,当然前提是这两个mapper的namespace是不样的(一般每个mapper都是不一

Mybatis中的一级缓存和二级缓存

1.概述 mybatis提供查询缓存主要是为了减轻了数据库的压力,提高了系统的性能. 缓存分为一级缓存和二级缓存,他们之间的关系和区别如下: 一级缓存是sqlSession级别的缓存.在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构(hashmap)对象缓存数据.不同的sqlSession之间的数据缓存区域是不互相影响的. 二级缓存是mapper级别的缓存.多个sqlSession去操作同一个mapper中的sql语句,多个sqlSession共享同一个Mapper的二级缓

【MyBatis学习12】MyBatis中的一级缓存

缓存的作用是减轻数据库的压力,提高数据库的性能的.mybatis中提供了一级缓存和二级缓存,先来看一下两个缓存的示意图: 从图中可以看出: 一级缓存是SqlSession级别的缓存.在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据.不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的. 二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级

SpringMVC + Mybatis + Shiro + ehcache时缓存管理器报错。

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'shiroFilter' defined in class path resource [spring/spring-shiro-web.xml]: Cannot resolve reference to bean 'securityManager' while setting bean property 'securit

【Hadoop学习】HDFS中的集中化缓存管理

Hadoop版本:2.6.0 本文系从官方文档翻译而来,转载请尊重译者的工作,注明以下链接: http://www.cnblogs.com/zhangningbo/p/4146398.html 概述 HDFS中的集中化缓存管理是一个明确的缓存机制,它允许用户指定要缓存的HDFS路径.NameNode会和保存着所需快数据的所有DataNode通信,并指导他们把块数据缓存在off-heap缓存中. HDFS集中化缓存管理具有许多重大优势: 1.明确的锁定可以阻止频繁使用的数据被从内存中清除.当工作集

mybatis0210 mybatis和ehcache缓存框架整合

1.1mybatis和ehcache缓存框架整合 一般不用mybatis来管理缓存而是用其他缓存框架在管理缓存,因为其他缓存框架管理缓存会更加高效,因为别人专业做缓存的而mybatis专业做sql语句的,mybatis二级缓存通过ehcache维护缓存数据. 1.1.1分布缓存 将缓存数据数据进行分布式管理.用户发起请求,首先会根据负载选择不同的服务器,如果用户在服务器1和服务器2都登录过,那么把用户的session分别放在服务器1和服务器2是不行的,所以就把用户的信息放在远程服务器集群中统一管