MyBatis 查询缓存

查询缓存作用,主要是为了 提高查询访问 速度。将用户对 同一数据的重复查询过程 简化,不再每次从 数据库查询获取结果数据, 从而提高访问速度。

MyBatis的查询缓存机制,根据缓存区的作用域生命周期)可以划分为2种:一级查询缓存和二级查询缓存

1、一级查询缓存

MyBatis一级查询缓存是基于org.apache.ibatis.catch.impl.PerpetualCache类的HsahMap本地缓存,其作用域SqlSession
当一个SqlSessoin结束后,该SqlSession中的一级查询缓存也就不存在了。
MyBatis默认一级查询缓存是开启状态,且不能关闭

一个SqlSession操作一个mapper.xml文件(sqlSession.getMapper(IStudentDao.class)),也就是说一个SqlSession对应一个namespace。但是一个namespace可以对多个SqlSession

1)证明SqlSession一级缓存是存在的

    @Test
    public void test01() {
        Student student = dao.selectById(2);
        System.out.println(student);

        Student student2 = dao.selectById(2);
        System.out.println(student2);
    }

2)测试输出:

[DEBUG] ==>  Preparing: select id,name,age,score from student where id = ? 
[DEBUG] ==> Parameters: 2(Integer)
[TRACE] <==    Columns: id, name, age, score
[TRACE] <==        Row: 2, 李四, 24, 94.5
[DEBUG] <==      Total: 1
Student [id=2, name=李四, age=24, score=94.5]
Student [id=2, name=李四, age=24, score=94.5]
第二次 查询没输出 sql语句,说明 没有查询 数据库,直接从 SqlSession的缓存中 查询数据

SqlSession缓存的底层实现是一个Map,Map的value查询结果
Map的key,即查询依据,不同的ORM框架,查询的依据是不同的
MyBatis查询依据是:SQLid + SQL语句
Hibernate查询依据是:查询结果对象id

3)增删改操作,无论是否提交,都会刷新一级缓存,使查询再次从DB中select

    @Test
    public void test03() {
        Student student = dao.selectById(2);
        System.out.println(student);

        // 增删改操作都会刷新SqlSession一级缓存【刷新缓存即清空缓存】,肯定要刷新缓存,不然从缓存读取可能是脏数据
        dao.insertStudent(new Student("哈哈", 91, 100));
        //    	sqlSession.commit(); //不提交不会写入数据库【不提交也同样会刷新缓存】

        Student student2 = dao.selectById(2);
        System.out.println(student2);
    }

4)测试输出

[DEBUG] ==>  Preparing: select id,name,age,score from student where id = ? 
[DEBUG] ==> Parameters: 2(Integer)
[TRACE] <==    Columns: id, name, age, score
[TRACE] <==        Row: 2, 李四, 24, 94.5
[DEBUG] <==      Total: 1
Student [id=2, name=李四, age=24, score=94.5]
[DEBUG] ==>  Preparing: insert into student(name,age,score) values(?,?,?) 
[DEBUG] ==> Parameters: 哈哈(String), 91(Integer), 100.0(Double)
[DEBUG] <==    Updates: 1
[DEBUG] ==>  Preparing: select id,name,age,score from student where id = ? 
[DEBUG] ==> Parameters: 2(Integer)
[TRACE] <==    Columns: id, name, age, score
[TRACE] <==        Row: 2, 李四, 24, 94.5
[DEBUG] <==      Total: 1
Student [id=2, name=李四, age=24, score=94.5]

2、二级查询缓存

1)内置二级缓存

MyBatis查询缓存的作用域根据映射文件mappernamespace划分的,相同namespacemapper查询数据存放在同一个缓存区域,不同namespace下的数据互不干扰
无论是一级缓存还是二级缓存都是按照namespace进行分别存放的。
不同之处在于,SqlSession一旦关闭,则SqlSession中缓存的数据将不存在,即一级缓存就不存在而二级缓存的生命周期会与整个应用同步。
开启内置二级缓存步骤:

a)Student实体类实现序列化接口

	public class Student implements Serializable {
		…………
	}

b)在mapper.xml映射文件中添加<cache />标签

<!-- 开启mybatis自带二级缓存 ,属性默认就行-->
<cache />

<cache />标签同样有属性,空代表使用默认属性,默认内置二级缓存。


eviction:逐出策略。

FIFO:先进先出

LRU: 未被使用时间最长的

flushInterval刷新缓存时间间隔,单位毫秒。刷新即清空缓存一般不指定,即当执行增删改操作时刷新缓存

readOnly:设置缓存中的对象是否只读

size:缓存中对象最多可以存放的个数

c)证明内置二级缓存是存在的

    @Test
    public void test01() {
        sqlSession = MyBatisUtils.getSqlSession();
        dao = sqlSession.getMapper(IStudentDao.class);

        Student student = dao.selectById(2);
        System.out.println(student);

        sqlSession.close();

        sqlSession = MyBatisUtils.getSqlSession();
        dao = sqlSession.getMapper(IStudentDao.class);
        Student student2 = dao.selectById(2);
        System.out.println(student2);
    }

sqlSession.close();   关闭之后,SqlSession一级缓存关闭了。

所以不会一级缓存查询,不开启二级缓存的话,会去数据库

d)测试输出:

[DEBUG] Cache Hit Ratio [com.xinm.mybatis.dao.IStudentDao]: 0.0
[DEBUG] ==>  Preparing: select id,name,age,score from student where id = ? 
[DEBUG] ==> Parameters: 2(Integer)
[TRACE] <==    Columns: id, name, age, score
[TRACE] <==        Row: 2, 李四, 24, 94.5
[DEBUG] <==      Total: 1
Student [id=2, name=李四, age=24, score=94.5]
[DEBUG] Cache Hit Ratio [com.xinm.mybatis.dao.IStudentDao]: 0.5
Student [id=2, name=李四, age=24, score=94.5]
CaChe Hit Ratio 缓存命中率,可以看出 二级缓存已经开启。

第一次命中率 0.0(没命中) ,第二次命中率0.5(命中) ,且没有执行Sql去数据库中查询。说明从缓存中查询

当然可以单独设置sql查询不使用缓存,那么就不会缓存数据,肯定也不会去缓存中查询数据

当然这里说的缓存二级缓存一级缓存MyBatis默认开启不能关闭,也不能设置

	<!-- 设置不使用缓存,默认为true -->	
	<select id="selectById2" resultType="Student" useCache="false">
	 	select id,name,age,score from student where id = #{xxx}
	</select>

e)增删改操作,同样会刷新二级缓存
1)对于二级缓存的清空
  不提交的情况: 不刷新二级缓存【只刷新了 value=null
     提交的情况: 刷新二级缓存【 key,value都清空,即删除 Entry对象】
2)对于一级缓存的清空
  都会刷新一级缓存,且 不能设置不刷新

当然也可以单独设置sql增删改操作不刷新缓存,当然这里说的缓存同样是二级缓存

	<!-- 不刷新二级缓存,默认为true刷新 -->
	<!-- SqlSession一级缓存,不可设置,增删改都会刷新一级缓存 -->
 	<insert id="insertStudent2" flushCache="false">
 		insert into student(name,age,score) values(#{name},#{age},#{score})
 	</insert>

f)二级缓存的关闭
1)全局关闭

	<settings>
		<!-- 二级缓存 总开关,不写默认代表开启 -->
		<setting name="cacheEnabled" value="false"/>
	</settings>

2)局部关闭

	<!-- 设置不使用缓存,默认为true -->	
	<select id="selectById2" resultType="Student" useCache="false">
	 	select id,name,age,score from student where id = #{xxx}
	</select>

g)二级缓存使用原则

1)只能在同一个命名空间(namespace)下使用
2)在
单表上使用
3)查询
远远多于修改时使用
h)总结:

一级缓存没有配置文件可以设置,因为MyBatis默认SqlSession一级缓存开启,且不能关闭,不能设置

二级缓存其实很少用,因为很多表都存在关联关系,必有关联查询。一般只对表查询】多更新】少的情况

2、ehCache二级查询缓存
MyBatis的 特长SQL操作, 缓存数据管理 不是其特长,为了 提高缓存的性能,MyBatis 允许使用 第三方缓存产品ehCache就是一种
a)使用ehCache二级缓存,实体类无需实现序列化接口。

b)用到2个jar包,一个是ehCache核心jar包,一个是MyBatis与ehCache整合的插件jar包
c)添加
ehcache.xml配置文件

ehCache核心jar包下面有一个ehcache-failsafe.xml拷贝重命名ehcache.xml,放在类路径下

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">

	<!-- 缓存在磁盘的路径 -->
	<!-- java.io.tmpdir 本地路径为:C:\Users\UserName\AppData\Local\Temp\ -->
    <diskStore path="java.io.tmpdir"/>
    <!-- <diskStore path="F:/ehcache"/> -->

	<defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            maxElementsOnDisk="10000000"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
        <persistence strategy="localTempSwap"/>
    </defaultCache>
    <!--
     maxElementsInMemory:指定内存缓存区可以存放的最大缓存对象个数
     eternal:设置缓存对象是否会过期。true表示永久不会过期,此时忽略timeToIdleSeconds和timeToLiveSeconds属性。默认为false
     timeToIdleSeconds:允许对象处于空闲状态的最长时间,单位为秒。设置为0,对象可以无限期的处于空闲状态
     timeToLiveSeconds:允许对象存在于缓存中的最长时间,单位为秒。设置为0,对象可以无限期的存在于缓存中
          注意只有timeToLiveSeconds >= timeToIdleSeconds 才有意义
     maxElementsOnDisk:指定硬盘缓存区可以存放的最大缓存对象个数
     diskExpiryThreadIntervalSeconds:指定硬盘中缓存对象的失效时间间隔
     memoryStoreEvictionPolicy:如果内存缓存区超过限制,选择移向硬盘缓存区中的对象时,使用的策略。
     							支持三种策略:
     							FIFO:First In First Out 先进先出
     							LFU:Less Frequently Used 最少使用
     							LRU:Less Recently Used 最近最少使用
     
     persistence:表示Cache的持久化,它只有一个属性strategy,表示当前Cache对应的持久化策略。其可选值如下:
		localTempSwap:当堆内存或者非堆内存里面的元素已经满了的时候,将其中的元素临时的存放在磁盘上,一旦重启就会消失。		localRestartable:该策略只对企业版Ehcache有用。它可以在重启的时候将堆内存或者非堆内存里面的元素持久化到硬盘上,重启之后再从硬盘上恢复元素到内存中。
		none:不持久化缓存的元素
		distributed:该策略不适用于单机,是用于分布式的。
     -->
</ehcache>

d)指定使用ehcache二级缓存

在映射文件mapper中的<cache />中通过type属性指定缓存机制为ehCache缓存

默认为MyBatis内置的二级缓存org.apache.ibatis.catch.impl.PerpetualCache

<!-- 开启mybatis自带二级缓存 或者 开启第三方缓存机制-->
 	<cache type="org.mybatis.caches.ehcache.EhcacheCache">
 		<!-- 可以进行个性化设置,不过仅仅是对当前namespace起作用 -->
 		<!-- /src/ehcache.xml 是对全局起作用 -->
 		<property name="timeToIdleSeconds" value="60"/>
 	</cache>

e)开启二级缓存

mybatis.xml主配置文件

	<settings>
		<!-- 二级缓存 总开关 , 不写表示默认开启 -->
		<setting name="cacheEnabled" value="true"/>
	</settings>

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MyBatis提供了查询缓存来减少数据库访问次数,提高性能。查询缓存是将查询结果缓存起来,当下次相同的查询被执行时,直接从缓存中获取结果,而不再访问数据库。 要启用查询缓存,需要在MyBatis配置文件中进行相关配置。以下是一些相关的配置选项: 1. `<setting name="cacheEnabled" value="true" />`:开启全局的二级缓存,默认为true。 2. `<mapper namespace="com.example.mapper" flushCache="true">`:在mapper中配置flushCache属性为true,表示刷新缓存,使其失效。 3. `<select id="selectUser" resultType="com.example.User" useCache="true">`:在查询语句中配置useCache属性为true,表示使用查询缓存。 默认情况下,MyBatis使用PerpetualCache作为二级缓存的实现,它是一个基于HashMap的缓存实现。MyBatis还支持其他的缓存实现,如Ehcache、Redis等。 需要注意的是,查询缓存是基于查询语句的完全匹配来判断是否使用缓存的。如果有任何一个参数发生变化,即使是相同的SQL语句,也会重新查询数据库而不使用缓存。 另外,MyBatis还提供了一级缓存,默认开启且无法关闭。一级缓存是基于SqlSession的,它的生命周期与SqlSession的生命周期一致,可以通过清除缓存的方式来使其失效。 总的来说,MyBatis查询缓存是一个简单但有效的机制,可以显著提高查询性能,减少数据库访问次数。但需要注意合理配置缓存策略,避免缓存过期或占用过多内存。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值