缓存机制

提高运行速度,提高查询效率

MyBatis包含--个非常强大的查询缓存特性它可以非常方便地配置和定制。缓存可以极大的提升查询效率。

mybatis中默认一级缓存

假如有一条数据的查询量非常大,且内容基本不变,那么反复查询就会让数据库压力变大,这时我们就可以将数据存在内存缓存中,这样就大大提高的了查询效率,同时缓解了数据库压力。

一级缓存(本地)和二级缓存(全局)


1、默认情况下,只有一级缓存( SqlSession级别的缓存也称为本地缓存)开启。
2、二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
3、为了提高扩展性。MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存

开始测试

1、一级缓存

(没有用到一级缓存的时候就,效果就是向数据库再次查询一次)

一定要开启log4j,不然看不到效果

引入log4j.jar包

<dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.12</version>
        </dependency>

把配置文件放在resource下

一定要log4j.properties命名,建议直接复制

# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE            debug   info   warn error fatal
log4j.rootCategory=debug, CONSOLE, LOGFILE

# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE

# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=d:/axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n


 在Mybatis中加配置

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bygRETnmoTku6PnoIHpk7o=,size_20,color_FFFFFF,t_70,g_se,x_16

 

<setting name="logImpl" value="STDOUT_LOGGING"/>

测试

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bygRETnmoTku6PnoIHpk7o=,size_20,color_FFFFFF,t_70,g_se,x_16

 watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bygRETnmoTku6PnoIHpk7o=,size_20,color_FFFFFF,t_70,g_se,x_16

 可以看出数据库只是执行了一次语句,但是同样输出两次结果,说明第二次是从内存之中直接获得的,连对象都是一样的

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bygRETnmoTku6PnoIHpk7o=,size_20,color_FFFFFF,t_70,g_se,x_16

 (1)SQLsession 不同也会再次查询

当SQLsession不一样时,我用新的SQLsession这时就不在缓存之中取结果了 

这说明每个SQLsession会有自己对应缓存

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bygRETnmoTku6PnoIHpk7o=,size_20,color_FFFFFF,t_70,g_se,x_16

(2)SQLsession 相同,但是查询条件不同

说白了就是缓存中还没有这条数据

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bygRETnmoTku6PnoIHpk7o=,size_20,color_FFFFFF,t_70,g_se,x_16

 (3)SQLsession 相同,两次查询间执行了增删改操作

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bygRETnmoTku6PnoIHpk7o=,size_20,color_FFFFFF,t_70,g_se,x_16

 明明是一样的查询却查询了两次

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bygRETnmoTku6PnoIHpk7o=,size_20,color_FFFFFF,t_70,g_se,x_16

 (4)SQLsession 相同,但是手动清除了缓存

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bygRETnmoTku6PnoIHpk7o=,size_20,color_FFFFFF,t_70,g_se,x_16

 同样执行了两次

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bygRETnmoTku6PnoIHpk7o=,size_20,color_FFFFFF,t_70,g_se,x_16

 

2、二级缓存(全局缓存)

基于namespace级别的缓存:一个namespace对应一个二级缓存;

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bygRETnmoTku6PnoIHpk7o=,size_20,color_FFFFFF,t_70,g_se,x_16

 

工作机制

1、一个会话,查询一条数据,这个数据会被放在当前会话的一级缓存中;

2、如果会话关闭:如果会话关闭; 一级缓存中的数据会被保存到二级缓存中;新的会话查询信息,就可以参照二级缓存

3、不同的namespace查出的数据会放在自己对应的缓存map中

效果:数据会从二级缓存中获取查出的数据都会被默认先放在一级缓存中。只有会话提交或者关闭以后,一级缓存中的数据才会转移到二级缓存中
 

开始测试

1、开启二级缓存

<setting name="cacheEnabled" value="true"/>

 watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bygRETnmoTku6PnoIHpk7o=,size_20,color_FFFFFF,t_70,g_se,x_16

 

 

 

eviction :缓存的回收策略:
LRU(默认) -最近最少使用的:移除最长时间不被使用的对象。
FIFO -先进先出:按对象进入缓存的顺序来移除它们。
SOFT -软引用:移除基于垃圾回收器状态和软引用规则的对象。
WEAK 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
flushInterval:缓存刷新间隔缓存多长时间清空一次,默认不清空,设置一个毫秒值
readOnly :是否只读:
        true:只读; mybatis认为所有从缓存中获取数据的操作都是只读操作,不会修改数据。mybatis为了加快获取速度,直接就会将数据在缓存中的引用交给用户。不安全,速度快
        false非只读: mybati s觉得获取的数据可能会被修改。mybatis会利用序列化&反序列的技术克隆一份新的数据给你。非常安全,但是速度慢

size存放多少元素

type:指定自定义缓存的全类名(默认即可)

2、去mapper.xml中配置

 

<cache eviction="FIFO" flushInterval="6000" readOnly="false" size="50" >

   </cache>

 

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bygRETnmoTku6PnoIHpk7o=,size_20,color_FFFFFF,t_70,g_se,x_16

3、对应的实体类要实现序列化接口

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bygRETnmoTku6PnoIHpk7o=,size_20,color_FFFFFF,t_70,g_se,x_16

测试

 watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bygRETnmoTku6PnoIHpk7o=,size_20,color_FFFFFF,t_70,g_se,x_16

 注意必须关闭会话,查询的内容才会放到二级缓存中,因为没有关闭的时候查询结果是存在一级缓存中的watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bygRETnmoTku6PnoIHpk7o=,size_20,color_FFFFFF,t_70,g_se,x_16

 watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bygRETnmoTku6PnoIHpk7o=,size_20,color_FFFFFF,t_70,g_se,x_16

将只读开启后结果相等 。

相关的设置

和缓存有关的设置/属性:

1)、cacheEnabled=true:false:关闭缓存(二级缓存关闭)(一级缓存一直可用的)

2)、每个select标签都有useCache="true": false:不使用缓存(一级缓存依然使用,二级缓存不使用)

3)、【每个增删改标签的:flushCache="true":(一级二级都会清除)】增删改执行完成后就会清楚缓存;

测试:flushCache="true":一级缓存就清空了;二级也会被清除; 查询标签:flushCache="false":如果flushCache=true;每次查询之后都会清空缓存;缓存是没有被使用的;

4)、sqlSession.clearCache();只是清楚当前session的一级缓存;

5)、localCacheScope:本地缓存作用域:(一级缓存SESSION);当前会话的所有数据保存在会话缓存中; STATEMENT:可以禁用一级缓存;

缓存原理图

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bygRETnmoTku6PnoIHpk7o=,size_20,color_FFFFFF,t_70,g_se,x_16

 

 

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐