Mybatis一级缓存、整合第三方缓存ehcache、Mybatis二级缓存

 2023-09-11 阅读 26 评论 0

摘要:8. 缓存 8.1 一级缓存 在对数据库的一次会话中,我们有可能会反复地执行完全相同的查询语句,如果不采取一些措施的话,每一次查询都会查询一次数据库,而我们在极短的时间内做了完全相同的查询,那么它们的结果极有可能完全相同,由于查

8. 缓存

8.1 一级缓存

在对数据库的一次会话中,我们有可能会反复地执行完全相同的查询语句,如果不采取一些措施的话,每一次查询都会查询一次数据库,而我们在极短的时间内做了完全相同的查询,那么它们的结果极有可能完全相同,由于查询一次数据库的代价很大,这有可能造成很大的资源浪费。

MyBatis会在一次会话的表示一个SqlSession对象中创建一个本地缓存(local cache),对于每一次查询,都会尝试根据查询的条件去本地缓存中查找是否在缓存中,如果在缓存中,就直接从缓存中取出,然后返回给用户;否则,从数据库读取数据,将查询结果存入缓存并返回给用户。

一级缓存和二级缓存速度、一级缓存是Mybatis自带的缓存。

如下面的测试代码:

@Testpublic void testFirstCache() {//连续查了两次id=21的数据//dept1从数据库中查询,控制台会打印sql语句Dept dept1 = session.selectOne("DEPT.getDeptById", 21);//dept2从缓存中查询,控制台上没有sql输出Dept dept2 = session.selectOne("DEPT.getDeptById", 21);System.out.println(dept1.getName());System.out.println(dept2.getName());}

这段代码执行一次查询。

redis如何保证缓存的数据是最新的、同一个SqlSession中,执行了任何一个update()、insert()、delete()或commit()后都会清空一级缓存。下面的测试代码会查询两次:

@Testpublic void testFirstCache() {//连续查了两次id=22的数据//dept1从数据库中查询,控制台会打印sql语句,放入缓存中Dept dept1 = session.selectOne("DEPT.getDeptById", 22);//使用进行增删改任何操作,或comimit()后都会清空缓存session.delete("DEPT.deleteDept", 27);session.commit();//因为前面进行了删除,所以缓存清空了,这里又会重新查询数据库Dept dept2 = session.selectOne("DEPT.getDeptById", 22);System.out.println(dept1.getName());System.out.println(dept2.getName());}

8.2 二级缓存

二级缓存需要用户去设置。二级缓存比一级缓存范围更大,一级缓存是一个SqlSession范围内的,不同的SqlSession之间不共享。而二级缓存可以实现多个SqlSession之间共享对同一个Mapper的缓存。

二级缓存需要在mybatis-config.xml中设置开启:

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

二级缓存有什么用、注意<settings>节点要写在typeAliases之前,否则会报错。

在需要开始二级缓存的Mapper中加入<cache>节点开启缓存。如在DeptMapper.xml中开启缓存:

<mapper namespace="DEPT"><!--开启本Mapper的二级缓存--><cache></cache>

二级缓存要求放入缓存的pojo对象都必须实现java.io.Serializable接口:

public class Dept implements Serializable{

java 本地缓存,测试代码:

@Testpublic void testSecondCache() {//使用session1查询dept1从数据库中查询,控制台会打印sql语句SqlSession session1=sessionFactory.openSession();Dept dept1 = session1.selectOne("DEPT.getDeptById", 28);session1.close();//关闭session1,此时将dept1写入二级缓存//开启一个新的sessionSqlSession session2=sessionFactory.openSession();//因为session1已经将id=28的对象放到二级缓存中了,所以这里从缓存中取Dept dept2 = session2.selectOne("DEPT.getDeptById", 28);System.out.println(dept1.getName());System.out.println(dept2.getName());session2.close();}

增删改查的statement标签都有一个flushCache属性,默认是true****,即执行后刷新缓存。一般不去改它。避免数据出现脏读。

<cache  eviction='FIFO' flushInterval='60000'  size='512' readOnly='true'/>

flushInterval(刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。

size(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的可用内存资源数目。默认值是1024。

readOnly(只读)属性可以被设置为true或false。只读的缓存会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false。

\1. LRU – 最近最少使用的:移除最长时间不被使用的对象。

\2. FIFO – 先进先出:按对象进入缓存的顺序来移除它们。

\3. SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。

\4. WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对

8.3 整合第三方缓存ehcache

ehcache缓存数据可以在内存和磁盘上缓存数据,无需担心容量问题。

Mybatis与ehcache结合使用,可以实现多个SqlSession对同一个Mapper的缓存共享。

8.3.1 导入jar包

使用ehcache需要导入jar包,在pom.xml中加入如下配置:

<dependency><groupId>net.sf.ehcache</groupId><artifactId>ehcache-core</artifactId><version>2.4.4</version>
</dependency><dependency><groupId>org.mybatis.caches</groupId><artifactId>mybatis-ehcache</artifactId><version>1.1.0</version>
</dependency>

8.3.2 创建ehcache配置文件

在resources目录下创建ehcache.xml文件:

<?xml version="1.0" encoding="UTF-8"?><ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:noNamespaceSchemaLocation="../bin/ehcache.xsd"><defaultCache overflowToDisk="true" eternal="false"/><!--硬盘上存放数据的位置--><diskStore path="E:/tmp"/><!--缓存的配置,与Mybatis整合时,name等于Mapper的namespace--><cache name="DEPT" overflowToDisk="true" eternal="false"timeToIdleSeconds="300" timeToLiveSeconds="600" maxElementsInMemory="2"maxElementsOnDisk="10" diskPersistent="true" diskExpiryThreadIntervalSeconds="300" diskSpoolBufferSizeMB="100" memoryStoreEvictionPolicy="LRU"/></ehcache>

参数说明:

name:Cache的唯一标识,与Mybatis结合使用时,name是Mapper的namespace

​ maxElementsInMemory:内存中最大缓存对象数

​ maxElementsOnDisk:磁盘中最大缓存对象数,若是0表示无穷大

​ eternal:Element是否永久有效,一但设置了,timeout将不起作用

​ overflowToDisk:配置此属性,当内存中Element数量达到maxElementsInMemory时,Ehcache将会Element写到磁盘中

​ timeToIdleSeconds:设置Element在失效前的允许闲置时间。仅当element不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大

​ timeToLiveSeconds:设置Element在失效前允许存活时间。最大时间介于创建时间和失效时间之间。仅当element不是永久有效时使用,默认是0.,也就是element存活时间无穷大

​ diskPersistent:是否缓存虚拟机重启期数据

​ diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒

​ diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区

​ memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。

8.3.3 开启Mybatis二级缓存

在mybatis-config.xml中开启二级缓存:

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

8.3.4 在Mapper中设置缓存

在DeptMapper.xml中开启缓存:

<mapper namespace="DEPT"><!--开启本Mapper的二级缓存--><!--<cache ></cache>--><cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

测试代码:

@Testpublic void testEhCache() throws InterruptedException {//使用session1查询dept1从数据库中查询,控制台会打印sql语句SqlSession session1 = sessionFactory.openSession();Dept dept1 = session1.selectOne("DEPT.getDeptById", 28);List<Dept> list1 = session1.selectList("DEPT.getAllDept");session1.close();//关闭session1,此时将dept1写入缓存//查看缓存是否生效CacheManager cacheManager = CacheManager.getInstance();if (cacheManager.cacheExists("DEPT")) {Cache cache = cacheManager.getCache("DEPT");//可以看到缓存中写入了数据System.out.println(cache.getKeys());}//开启一个新的sessionSqlSession session2 = sessionFactory.openSession();//因为session1已经将id=28的对象放到二级缓存中了,所以这里从缓存中取//使用session2执行和session1一样的语句时,不会打印sqlDept dept2 = session2.selectOne("DEPT.getDeptById", 28);List<Dept> list2 = session2.selectList("DEPT.getAllDept");session2.close();
}

运行结果:
在这里插入图片描述
去磁盘上查看,可以看到缓存文件:
在这里插入图片描述

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/3/47731.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息