MyBatis的cache缓存

发布于:2023-01-04 ⋅ 阅读:(290) ⋅ 点赞:(0)


什么是缓存:

缓存是计算机中的一块存储区域,把数据放入到存储区域中,读取速度快


一、MyBatis的缓存

  1. MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。
  2. 默认情况下是没有开启缓存的,除了局部的 session 缓存,可以增强变现而且处理循环 依赖也是必须的。要开启二级缓存,你需要在你的 SQL 映射文件中添加一行: <cache/>

1、什么是一级缓存? 为什么使用一级缓存?

  1. 每当我们使用MyBatis开启一次和数据库的会话,MyBatis会创建出一个SqlSession对象表示一次数据库会话。

  2. 在对数据库的一次会话中,我们有可能会反复地执行完全相同的查询语句,如果不采取一些措施的话,每一次查询都会查询一次数据库,而我们在极短的时间内做了完全相同的查询,那么它们的结果极有可能完全相同,由于查询一次数据库的代价很大,这有可能造成很大的资源浪费。
  3. 为了解决这一问题,减少资源的浪费,MyBatis会在表示会话的SqlSession对象中建立一个简单的缓存,将每次查询到的结果缓存起来, 当下次查询的时候,如果判断先前有个完全一样的查询,会直接从缓存中将结果取出,返回给用户,不需要再进行一次数据库查询了。
  4. 如下图所示,MyBatis会在一次会话的表示----一个SqlSession对象中创建一个本地缓存(local cache),对于每一次查询,都会尝试根据查询的条件去本地缓存中查找是否存在,如果在缓存中,就直接从缓存中取出,然后返回给用户;否则,从数据库读取数据,将查询结果存入缓存并返回给用户。(对于会话(Session)级别的数据缓存,我们称之为一级数据缓存,简称一级缓存

1)一级缓存

2)MyBatis中的一级缓存组织

SqlSession对象、Executor对象、Cache对象之间的关系如下图所示:

 PepetualCache的代码实现:

 PerpetualCache实现原理其实很简单,其内部就是通过一个简单的HashMap<k,v>来实现的,没有其他的任何限制。

3)一级缓存的生命周期

  •    a.MyBatis在开启一个数据库会话时,会创建一个新的SqlSession对象,SqlSession对象中会有一个新的Executor对象,Executor对象中持有一个新的PerpetualCache对象;当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉。
    • d.SqlSession中执行了任何一个update操作(update()、delete()、insert()),都会清空PerpetualCache对象的数据,但是该对象可以继续使用;
    • c.如果SqlSession调用了clearCache()会清空PerpetualCache对象中的数据,但是该对象仍可使用;
    • b.如果SqlSession调用了close()方法会释放掉一级缓存PerpetualCache对象,一级缓存将不可用;

4)一级缓存的工作流程 

  1. 对于某个查询,根据statementId,params,rowBounds来构建一个key值,根据这个key值去缓存Cache中取出对应的key值存储的缓存结果;
  2. 判断从Cache中根据特定的key值取的数据数据是否为空,即是否命中;如果命中,则直接将缓存结果返回;
  3. 如果没命中:

        去数据库中查询数据,得到查询的结果;

        将key和查询到的结果分别作为key,value对,存储到Cache中;

        将查询结果返回给用户。

  4.结束

5)Cache中Map的key值:CacheKey

  1. 我们知道,Cache最核心的实现其实就是一个Map,将本次查询使用的特征值作为key,将查询结果作为value存储到Map中。
  2. 现在最核心的问题出现了:怎样来确定一次查询的特征值?
  3. 换句话说就是:怎样判断某两次查询是完全相同的查询?
  4. 也可以这样说:如何确定Cache中的key值?
  5. MyBatis认为,对于两次查询,如果以下条件都完全一样,那么就认为它们是完全相同的两次查询:      
  • 传入的statementId对于MyBatis而言,你要使用它,必须需要一个statementId,它代表着你将执行什么样的Sql;
  • 查询时要求的结果集中的结果范围(结果的范围通过rowBounds.offset和rowBounds.limit表示);
  • 这次查询所产生的最终要传递给JDBC java.sql.Preparedstatement的Sql语句字符串(boundSql.getSql())
  • 传递给java.sql.Statement要设置的参数值
  • 综上所述,CacheKey由以下条件决定:statementId +rowBounds +传递给JDBC的SQL +传递给JDBC的参数值

2、二级缓存图示

1.缓存图1,MyBatis的二级缓存是Application级别的缓存,它可以提高对数据库查询的效率,以提高应用的性能。

 2、二级缓存图2

CachingExecutor是Executor的装饰者,以增强Executor的功能,使其具有缓存查询的功能,这里用到了设计模式中的装饰者模式。

 1)二级缓存的相关配置

要想使某条Select查询支持二级缓存,你需要保证:

1.MyBatis支持二级缓存的总开关:全局配置变量参数cacheEnabled=true

2.该select语句所在的Mapper,配置了<cache> 或<cached-ref>节点,并且有效

3.该select语句的参数useCache=true 4.对象的类必须实现序列化接口

一级缓存和二级缓存的使用顺序 : 二级缓存———> 一级缓存——> 数据库

二级缓存作用域为 Mapper(Namespace);

configuration.MappedStatement.Cache;项目启动时会初始化;

2)二级缓存实现的选择 

使用MyBatis的二级缓存有三个选择:

1.MyBatis自身提供的缓存实现;

2.用户自定义的Cache接口实现;(集成Cache 接口)

3.跟第三方内存缓存库的集成;

 

 

3.Cache使用时的注意事项/避免使用二级缓存

注意事项:

  1. 只能在【只有单表操作】的表上使用缓存,不只是要保证这个表在整个系统中只有单表操作,而且和该表有关的全部操作必须全部在一个namespace下。
  2. 在可以保证查询远远大于insert,update,delete操作的情况下使用缓存这一点不需要多说,所有人都应该清楚。记住,这一点需要保证在1的前提下才可以!

避免使用二级缓存:

  1. 可能会有很多人不理解这里,二级缓存带来的好处远远比不上他所隐藏的危害。
  2. 缓存是以namespace为单位的,不同namespace下的操作互不影响。
  3. insert,update,delete操作会清空所在namespace下的全部缓存。
  4. 通常使用MyBatis Generator生成的代码中,都是各个表独立的,每个表都有自己的namespace。

4.使用MyBatis的二级缓存有三个选择:

  • MyBatis自身提供的缓存实现;
  • 用户自定义的Cache接口实现;(集成Cache 接口)
  • 跟第三方内存缓存库的集成;

5.了解缓存redis

  • Redis 可以存储键和五种不同类型的值之间的映射。键的类型只能为字符串,值支持五种数据类型:字符串、列表、集合、散列表、有序集合。
  • 与传统数据库不同的是 Redis 的数据是存在内存中的,所以读写速度非常快,因此 redis 被广泛应用于缓存方向,每秒可以处理超过 10万次读写操作,是已知性能最快的Key-Value DB。另外,Redis 也经常用来做分布式锁。除此之外,Redis 支持事务 、持久化、LUA脚本、LRU驱动事件、

6.mybatis 和 hibernate 的区别有哪些?

  • Mybatis和hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句。
  •  Mybatis直接编写原生态sql,可以严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,因为这类软件需求变化频繁,一但需求变化要求迅速输出成果。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件,则需要自定义多套sql映射文件,工作量大。 
  •  Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件,如果用hibernate开发可以节省很多代码,提高效率。

总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到