长春建设工程信息网站,科技公司网站模板官网,站长统计幸福宝,免费网站建设市场文章目录MyBatis的缓存1、缓存概述2、MyBatis的一级缓存2.1 一级缓存的使用2.2 一级缓存的失效3、MyBatis的二级缓存3.1 二级缓存的开启3.2 二级缓存的失效3.2 二级缓存相关配置4、系统缓存的查询顺序5、EHCache的使用5.1 EHCache基本介绍5.2 EHCache的基本使用5.3 EHCache配置…
文章目录MyBatis的缓存1、缓存概述2、MyBatis的一级缓存2.1 一级缓存的使用2.2 一级缓存的失效3、MyBatis的二级缓存3.1 二级缓存的开启3.2 二级缓存的失效3.2 二级缓存相关配置4、系统缓存的查询顺序5、EHCache的使用5.1 EHCache基本介绍5.2 EHCache的基本使用5.3 EHCache配置文件参数详解MyBatis的缓存
1、缓存概述 什么是缓存 缓存存储在计算机上的一个原始数据复制集就是数据交换的缓冲区称作Cache是存贮数据使用频繁的数据的临时地方。当用户查询数据首先在缓存中寻找如果找到了则直接执行。如果找不到则去数据库中查找。 缓存有什么用 缓存的本质就是用空间换时间牺牲数据的实时性以服务器内存中的数据暂时代替从数据库读取最新的数据减少数据库IO减轻服务器压力减少网络延迟加快页面打开速度。 缓存的分类 文件缓存文件缓存是把一些需要高速存取的变量缓存在内存中。模板引擎用的就是文件缓存机制把动态代码编译成静态文件放入硬盘不用每次访问都编译直接读出即可。浏览器缓存浏览器缓存根据一套与服务器约定的规则进行工作在同一个会话过程中会检查一次并确定缓存的副本足够新。如果在浏览过程中前进或后退时访问到同一个图片这些图片可以从浏览器缓存中调出而即时显示。数据库缓存常用的缓存方案有memcached、redis等。把经常需要从数据库查询的数据、或经常更新的数据放入到缓存中这样下次查询时直接从缓存直接返回减轻数据库压力提升数据库性能。Web应用层缓存应用层缓存指的是从代码层面上通过代码逻辑和缓存策略实现对数据、页面、图片等资源的缓存可以根据实际情况选择将数据存在文件系统或者内存中减少数据库查询或者读写瓶颈提高响应效率。服务器缓存包括代理服务器缓存和CDN缓存。 代理服务器缓存代理服务器是浏览器和源服务器之间的中间服务器浏览器先向这个中间服务器发起Web请求经过处理后(比如权限验证缓存匹配等)再将请求转发到源服务器。CDN缓存也叫网关缓存、反向代理缓存。CDN缓存一般是由网站管理员自己部署为了让他们的网站更容易扩展并获得更好的性能。 MyBatis的缓存属于Web应用层缓存在MyBatis中缓存被分为两大类系统缓存和自定义缓存 系统缓存是MyBatis中自带的缓存这些缓存都是MyBatis帮我们设计好了的直接就能用主要包含一级缓存和二级缓存自定义缓存顾名思义就是自己定义的缓存需要自己手动去设计当然一般而言我们并不会真正的区设计一个缓存而是直接使用第三方设计的缓存比如Redis、Enhance等 2、MyBatis的一级缓存 一级缓存一级缓存是默认开启的它的范围是SqlSession级别的当我们用SqlSession来查询数据的时候如果下一次再使用相同的SqlSession进行查询的时候就会直接从缓存中取数据如果没有才从数据库中取数据缓存只针对查询功能有效 2.1 一级缓存的使用
示例
import com.hhxy.mapper.CacheMapper;
import com.hhxy.pojo.Emp;
import com.hhxy.utils.SqlSessionFactoryUtil;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.Test;/*** author ghp* date 2022/9/9*/
public class CacheMapperTest {Testpublic void cacheMapperTest(){//1、获取SqlSessionFactory对象SqlSessionFactory sqlSF SqlSessionFactoryUtil.getSqlSF();//2、获取SqlSession对象SqlSession sqlS1 sqlSF.openSession();SqlSession sqlS2 sqlSF.openSession();//3、获取Mapper接口对象CacheMapper mapper1 sqlS1.getMapper(CacheMapper.class);CacheMapper mapper2 sqlS2.getMapper(CacheMapper.class);//4、执行SQLint empId 20;/*使用SqlSession1执行SQL*/Emp emp1 mapper1.getEmpById(empId);System.out.println(emp1 emp1);Emp emp2 mapper1.getEmpById(empId);System.out.println(emp2 emp2);/*使用SqlSession2执行SQL*/Emp emp3 mapper2.getEmpById(empId);System.out.println(emp3 emp3);//5、释放资源}
}2.2 一级缓存的失效
使一级缓存失效的四种情况 不同的SqlSession对应不同的一级缓存 这是由一级缓存的级别决定的详情见上面的示例不在赘述 同一个SqlSession但是查询条件不同 这个也很好理解不同条件查询得到的数据是不一致的 同一个SqlSession两次查询期间执行了任何一次增删改操作 因为增、删、改会清空一级缓存原因缓存中的数据毕竟不是数据库中的即时数据在执行增删改操作后可能会影响到我们上一次刚查询的数据此时缓存中的数据就已经过时了比如进行第一次查询数据进入缓存但进行一个删除操作后将这条进入缓存的数据从数据库中删除了第二次查询这条数据已经不存在了直接使用缓存中的数据显然的错误的所以MyBatis干脆就规定了增删改后直接清空一级缓存这样就能保证二次查询的正确性 同一个SqlSession两次查询期间手动清空了缓存 //清空一级缓存的代码
sqlSession.clearCache();3、MyBatis的二级缓存 二级缓存二级缓存需要手动开启它的范围是SqlSessionFactory级别的通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存此后若再次执行相同的查询语句结果就会从缓存中获取 3.1 二级缓存的开启 二级缓存的开启条件 在核心配置文件中设置全局配置属性cacheEnabledtrue默认为true不需要设置 setting namecacheEnabled valuetrue/在映射文件中设置标签 cache/ 二级缓存必须在SqlSession关闭或提交之后有效不进行关闭或提交则查询的数据会自动进入一级缓存 查询的数据所转换的实体类类型必须实现序列化的接口否则报java.io.NotSerializableException: com.hhxy.pojo.Emp异常
示例
二级缓存测试代码
import com.hhxy.mapper.CacheMapper;
import com.hhxy.pojo.Emp;
import com.hhxy.utils.SqlSessionFactoryUtil;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.Test;/*** author ghp* date 2022/9/9*/
public class CacheMapperTest {Testpublic void cacheMapperTest(){//1、获取SqlSessionFactory对象SqlSessionFactory sqlSF SqlSessionFactoryUtil.getSqlSF();//2、获取SqlSession对象SqlSession sqlS1 sqlSF.openSession();SqlSession sqlS2 sqlSF.openSession();//3、获取Mapper接口对象CacheMapper mapper1 sqlS1.getMapper(CacheMapper.class);CacheMapper mapper2 sqlS2.getMapper(CacheMapper.class);//4、执行SQLint empId 20;/*使用SqlSession1执行SQL*/Emp emp1 mapper1.getEmpById(empId);System.out.println(emp1 emp1);sqlS1.close();//如果去掉这句话就会执行两遍SQL/*使用SqlSession2执行SQL*/Emp emp2 mapper2.getEmpById(empId);System.out.println(emp3 emp2);//5、释放资源}
}备注只有二级缓存才会输出缓存命中率
3.2 二级缓存的失效 使二级缓存失效的情况 两次查询之间执行了任意的增、删、改会使一级和二级缓存同时失效 因为增、删、改清除了二级缓存当第二次进行查询时先到缓存区中寻找是否具有所需数据结果由于缓存区被清空了所以重新执行SQL语句到数据库中查询并获取数据
3.2 二级缓存相关配置 在mapper配置文件中添加的cache标签可以设置一些属性 eviction属性缓存回收策略默认的是 LRU LRULeast Recently Used最近最少使用的移除最长时间不被使用的对象FIFOFirst in First out先进先出按对象进入缓存的顺序来移除它们SOFT 软引用1内存不足时回收JVM会根据当前堆的使用情况来判断何时回收一般当缓存溢出时就会回收软引用的对象WEAKReference弱引用GC触发就回收JVM一旦发现使用弱引用规则指向的对象就会直接回收StrongReference强引用不会被回收JVM宁愿抛出异常也不会回收使用强引用规则指向的对象这是Java中最普遍的引用PhantomReference虚引用虚引用主要用来跟踪对象的回收并不影响对象的生命周期使用虚引用规则指向的对象可能随时被回收 推荐阅读 页面置换算法相关概念和计算详细解说LRU算法和FIFO算法 强、软、弱、虚引用的区别和使用 - 知乎 (zhihu.com) Java强引用软引用弱引用和虚引用 flushInterval属性刷新间隔单位为毫秒。默认是不设置也就是没有刷新间隔只有缓存被调用时进行刷新 size属性引用数目为正整数。代表缓存最多可以存储多少个对象太大容易导致内存溢出太小缓存没什么意义所以一般使用默认的 readOnly属性只读取值为boolean类型默认是false true只读缓存会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。 因为返回缓存对象的相同实例所以才会将他设置成只读因为返回缓存对象的相同实例时如果调用者对这个对象进行修改会导致直接修改掉缓存中的对象存在安全隐患只读就能解决这种安全隐患性能优势是相较于取值时false的状态而言的 因为读写缓存是返回一个缓存对象的拷贝准确来说是深拷贝拷贝是需要耗费时间、以及资源的 false读写缓存会返回缓存对象的拷贝通过序列化。这会慢一些但是安全因此默认是 false。 这种方式能进行读写缓存的原因是因为返回的对象是缓存对象的拷贝当我们对缓存对象进行修改时由于是深拷贝返回的缓存对象的修改并不会影响到缓存中的对象所以更安全但是相较于只读缓存性能更低
4、系统缓存的查询顺序
二级缓存→一级缓存二级缓存 \to 一级缓存二级缓存→一级缓存 先查询二级缓存 原因二级缓存的范围更大二级缓存是SqlSessionFactory级别的而一级缓存是SqlSession级别的二级缓存中可能会有其他程序已经查出来的数据可以拿来直接使用 如果二级缓存没有命中再查询一级缓存 原因一级缓存有二级缓存中没有的数据二级缓存虽然范围比一级缓存大但并不包含所有的一级缓存二级缓存必须使用close()方法后才能将数据读取到二级缓存中有一些没有使用close()方法的查询结果只在一级缓存中 如果一级缓存也没有命中则查询数据库 SqlSession关闭之后一级缓存中的数据会写入二级缓
5、EHCache的使用 5.1 EHCache基本介绍 EHCache是什么? EhCache 是一个纯Java的进程内缓存框架具有快速、精干等特点是Hibernate2中默认的CacheProvider3。 Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。它具有内存和磁盘存储缓存加载器,缓存扩展,缓存异常处理程序,一个gzip缓存servlet过滤器,支持REST和SOAP api等特点。 EHCache官网EHCache Hibernate介绍Hibernate 中文文档 | Hibernate 中文网 EHCache的作用 EHCache是SqlSessionFactory级别提供二级缓存的功能相较MyBatis自带的二级缓存具有更加优秀的性能。 EHCache的特点 使用起来快速、简单、灵活。因为是框架嘛当然具有框架的一般特点使用简单灵活性是EHCache具有多种缓存策略同时缓存数据有两级内存和磁盘因此无需担心容量问题健壮性、扩展性。分布式。可以通过RMI、可插入API等方式进行分布式缓存支持多缓存管理器实例以及一个实例的多个缓存区域 ……
PS这些所谓的特点只需要了解即可重点还是会使用当你能够熟练使用多个缓存时你就能自然而然地明白它的特点了
5.2 EHCache的基本使用
#mermaid-svg-dvfCL5jdWDTXCOC6 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-dvfCL5jdWDTXCOC6 .error-icon{fill:#552222;}#mermaid-svg-dvfCL5jdWDTXCOC6 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-dvfCL5jdWDTXCOC6 .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-dvfCL5jdWDTXCOC6 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-dvfCL5jdWDTXCOC6 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-dvfCL5jdWDTXCOC6 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-dvfCL5jdWDTXCOC6 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-dvfCL5jdWDTXCOC6 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-dvfCL5jdWDTXCOC6 .marker.cross{stroke:#333333;}#mermaid-svg-dvfCL5jdWDTXCOC6 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-dvfCL5jdWDTXCOC6 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-dvfCL5jdWDTXCOC6 .cluster-label text{fill:#333;}#mermaid-svg-dvfCL5jdWDTXCOC6 .cluster-label span{color:#333;}#mermaid-svg-dvfCL5jdWDTXCOC6 .label text,#mermaid-svg-dvfCL5jdWDTXCOC6 span{fill:#333;color:#333;}#mermaid-svg-dvfCL5jdWDTXCOC6 .node rect,#mermaid-svg-dvfCL5jdWDTXCOC6 .node circle,#mermaid-svg-dvfCL5jdWDTXCOC6 .node ellipse,#mermaid-svg-dvfCL5jdWDTXCOC6 .node polygon,#mermaid-svg-dvfCL5jdWDTXCOC6 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-dvfCL5jdWDTXCOC6 .node .label{text-align:center;}#mermaid-svg-dvfCL5jdWDTXCOC6 .node.clickable{cursor:pointer;}#mermaid-svg-dvfCL5jdWDTXCOC6 .arrowheadPath{fill:#333333;}#mermaid-svg-dvfCL5jdWDTXCOC6 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-dvfCL5jdWDTXCOC6 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-dvfCL5jdWDTXCOC6 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-dvfCL5jdWDTXCOC6 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-dvfCL5jdWDTXCOC6 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-dvfCL5jdWDTXCOC6 .cluster text{fill:#333;}#mermaid-svg-dvfCL5jdWDTXCOC6 .cluster span{color:#333;}#mermaid-svg-dvfCL5jdWDTXCOC6 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-dvfCL5jdWDTXCOC6 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}创建Maven工程导入依赖编写ehcache配置文件编写logback配置文件编写Java代码编写MyBatis配置文件Step1创建Maven工程 目录结构 Step2导入依赖 EHCache所需依赖 !--mysql驱动--dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion8.0.16/version/dependency!--mybatis--dependencygroupIdorg.mybatis/groupIdartifactIdmybatis/artifactIdversion3.5.10/version/dependency!-- Mybatis EHCache整合包 --dependencygroupIdorg.mybatis.caches/groupIdartifactIdmybatis-ehcache/artifactIdversion1.2.2/version/dependency!-- slf4j日志门面的一个具体实现 --dependencygroupIdch.qos.logback/groupIdartifactIdlogback-classic/artifactIdversion1.2.3/version/dependency备注日志门面就是日志提供的接口这里说的就是slf4j-api即要使用EHCache必须先实现slf4j-apislf4j日志门面但是EHCache却没有实现slf4j-api所以需要我们导入第三方slf4j-api的实现也就是logback-classic 这个可以在Maven中看到EHCache中是有slf4j的 推荐阅读浅谈日志门面 Step3编写MyBatis配置文件 略…… 推荐阅读快速上手MyBatis该文通俗易懂步骤说明详细是很适合快速上手MyBatis的不二之选 Step4编写ehcache配置文件 ehcache.xml ?xml version1.0 encodingutf-8 ?
ehcache xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:noNamespaceSchemaLocation../config/ehcache.xsd!-- 磁盘保存路径 --diskStore pathD:\Test\ehcache/defaultCachemaxElementsInMemory1000maxElementsOnDisk10000000eternalfalseoverflowToDisktruetimeToIdleSeconds120timeToLiveSeconds120diskExpiryThreadIntervalSeconds120memoryStoreEvictionPolicyLRU/defaultCache
/ehcacheStep5编写logback配置文件 logback.xml: ?xml version1.0 encodingUTF-8?
configuration debugtrue!-- 指定日志输出的位置 --appender nameSTDOUT classch.qos.logback.core.ConsoleAppenderencoder!-- 日志输出的格式 --!-- 按照顺序分别是 时间、日志级别、线程名称、打印日志的类、日志主体内容、换行--pattern[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger][%msg]%n/pattern/encoder/appender!-- 设置全局日志级别。日志级别按顺序分别是 DEBUG、INFO、WARN、ERROR --!-- 指定任何一个日志级别都只打印当前级别和后面级别的日志。 --root levelDEBUG!-- 指定打印日志的appender这里通过“STDOUT”引用了前面配置的appender --appender-ref refSTDOUT //root!-- 根据特殊需求指定局部日志级别 --logger namecom.atguigu.crowd.mapper levelDEBUG/
/configurationStep6编写Java代码 这里可以直接使用前面测试二级缓存的代码因为他们都是属于二级缓存所以我们就直接看测试结果吧(●’◡’●) 1不在中间使用删除方法 2在中间使用删除方法
5.3 EHCache配置文件参数详解
参数名作用maxElementsInMemory设置在内存中缓存的element的最大数目maxElementsOnDisk设置在磁盘上缓存的element的最大数目其中0表示无穷大etenrnal设定缓存的elements是否永远不过期。 如果为 true则缓存的数据始终有效 如果为false那么还 要根据timeToIdleSeconds、timeToLiveSeconds 判断overflowToDisk设定当内存缓存溢出的时候是否将过期的element 缓存到磁盘上timeToIdleSeconds当缓存在EhCache中的数据前后两次访问的时间超 过timeToIdleSeconds的属性取值时 这些数据便 会删除默认值是0,也就是可闲置时间无穷大timeToLiveSeconds缓存element的有效生命期默认是0.,也就是 element存活时间无穷大diskSpoolBufferDiskStore(磁盘缓存)的缓存区大小。默认是 30MB。每个Cache都应该有自己的一个缓冲区diskPersistend在VM重启的时候是否启用磁盘保存EhCache中的数 据默认是falsediskExpiryThreadIntervalSeconds磁盘缓存的清理线程运行间隔默认是120秒。每 个120s 相应的线程会进行一次EhCache中数据的 清理工作memoryStoreEvictionPolicy当内存缓存达到最大有新的element加入的时 候 移除缓存中element的策略。 默认是LRU 最 近最少使用可选的有LFU 最不常使用和 FIFO 先进先出
备注颜色加深的是必须参数 推荐阅读页面置换算法相关概念和计算含LRU、LFU和FIFO三个算法的详解 参考文章 究竟什么是缓存 - 知乎 (zhihu.com)架构成长系列缓存的分类 - 知乎 (zhihu.com)缓存及其分类页面置换算法相关概念和计算强、软、弱、虚引用的区别和使用 - 知乎 (zhihu.com)Ehcache 入门详解MyBatis的基本使用浅谈日志门面页面置换算法相关概念和计算(4条消息) Java强引用软引用弱引用和虚引用_瞧德的博客-CSDN博客_强引用弱引用软引用和虚引用 Java中的引用一般是指变量对对象的引用栈中的变量引用堆中的对象让变量拥有对象的属性和行为这个变量和对象的这种关系叫做引用 ↩︎ Hibernate和MyBatis一样都是ORM框架同属于持久层也叫数据访问层的框架 ↩︎ CacheProvider缓存提供者是Java缓存中的一个提供缓存技术的角色主要用来提供缓存功能 ↩︎