mybatis缓存机制详解 #yyds干货盘点#
Posted 梁云亮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mybatis缓存机制详解 #yyds干货盘点#相关的知识,希望对你有一定的参考价值。
mybatis提供了缓存机制减轻数据库压力,提高数据库性能。mybatis的缓存分为一级和二级两种:
- 一级缓存:SqlSession级别的缓存,缓存的数据只在SqlSession内有效
- 二级缓存:mapper级别的缓存,同一个namespace公用这一个缓存,所以对SqlSession是共享的
一级缓存:
一级缓存是基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该 Session 中的所有 Cache 就将清空。
一级缓存是SqlSession级别的缓存,在操作数据库的时候需要先创建SqlSession会话对象,在对象中有一个HashMap用于存储缓存数据,此HashMap是当前会话对象私有的,别的SqlSession会话对象无法访问。
一级缓存是基于SQLSession的缓存,一级缓存的内容不能跨SQLSession。由mybatis自动维护。不同的sqlsession之间的缓存区域是互相不影响的。
具体流程:
- 第一次执行select完毕会将查到的数据写入SqlSession内的HashMap中缓存起来
- 第二次执行select会从缓存中查数据,如果select相同且传参数一样,那么就能从缓存中返回数据,不用去数据库了,从而提高了效率
注意事项:
- mybatis默认是开启一级缓存,不需要配置
- 如果SqlSession执行了DML操作(insert、update、delete),并commit了,那么mybatis就会清空当前SqlSession缓存中的所有缓存数据,这样可以保证缓存中存的数据永远和数据库中一致,避免出现脏读
- 一个SqlSession结束后那么它里面的一级缓存也就不存在了。
- mybatis的缓存是基于
[namespace:sql语句:参数]
来进行缓存的。意思就是,SqlSession的HashMap存储缓存数据时,是使用[namespace:sql:参数]
作为key,查询返回的语句作为value保存的。
二级缓存:
二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap 存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。作用域为 namespance 是指对该 namespance 对应的配置文件中所有的 select 操作结果都缓存,这样不同线程之间就可以共用二级缓存。
二级缓存可以设置返回的缓存对象策略:
- 当 readOnly="true"时,表示二级缓存返回给所有调用者同一个缓存对象实例,调用者可以 update 获取的缓存实例,但是这样可能会造成其他调用者出现数据不一致的情况(因为所有调用者调用的是同一个实例)。
- 当 readOnly="false"(默认)时,返回给调用者的是二级缓存总缓存对象的拷贝,即不同调用者获取的是缓存对象不同的实例,这样调用者对各自的缓存对象的修改不会影响到其他的调用者,即是安全的。
二级缓存是mapper级别的缓存,也就是同一个namespace中的mappe.xml。当多个SqlSession使用同一个Mapper操作数据库的时候,得到的数据会缓存在同一个二级缓存区域。
二级缓存是基于映射文件的缓存(namespace),缓存范围比一级缓存更大,不同的SQLSession可以访问二级缓存的内容。哪些数据放入二级缓存需要自己指定。
二级缓存默认是没有开启的。需要在setting全局参数中配置开启二级缓存
<settings>
<setting name="cacheEnabled" value="true"/> <!--默认是false:关闭二级缓存-->
<settings>
在mapper.xml中配置:
<cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>
这里配置了一个LRU缓存,并每隔60秒刷新,最大存储512个对象,而却返回的对象是只读的。
- eviction:代表的是缓存回收策略,目前MyBatis提供以下策略:
- LRU(Least Recently Used):最近最少使用的,最长时间不用的对象
- FIFO(First In First Out):先进先出,按对象进入缓存的顺序来移除他们
- SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象
- WEAK:弱引用,更积极的移除基于垃圾收集器状态和弱引用规则的对象。这里采用的是LRU,
移除最长时间不用的对形象
- flushInterval:刷新间隔时间,单位为毫秒,这里配置的是60000秒刷新,如果你不配置它,那么当
SQL被执行的时候才会去刷新缓存。 - size:引用数目,一个正整数,代表缓存最多可以存储多少个对象,不宜设置过大。设置过大会导致内存溢出。
- readOnly:只读,意味着缓存数据只能读取而不能修改,这样设置的好处是我们可以快速读取缓存,缺点是我们没有办法修改缓存,他的默认值是false,不允许我们修改。
对于访问多的查询请求并且用户对查询结果实时性要求不高的情况下,可采用mybatis二级缓存,降低数据库访问量,提高访问速度。
若想禁用当前select语句的二级缓存,添加useCache="false"(默认情况下为true)就可以了:
<select id="getUserById" parameterType="int" resultType="user" useCache="false">
在实际开发中,针对每次查询都需要最新数据的sql,要设置为useCache=“false” ,禁用二级缓存
具体流程:
- 当一个sqlseesion执行了一次select后,关闭此session的时候,会将查询结果缓存到二级缓存
- 当另一个sqlsession执行select时,首先会在他自己的一级缓存中找,如果没找到,就回去二级缓存中找,找到了就返回,就不用去数据库了,从而减少了数据库压力提高了性能
注意事项:
- 如果SqlSession执行了DML操作(insert、update、delete),并commit了,那么mybatis就会清空当前mapper缓存中的所有缓存数据,这样可以保证缓存中的存的数据永远和数据库中一致,避免出现脏读
- mybatis的缓存是基于
[namespace:sql语句:参数]
来进行缓存的,意思就是,SqlSession的HashMap存储缓存数据时,是使用[namespace:sql:参数]
作为key,查询返回的语句作为value保存的。
二级缓存的局限性
mybatis二级缓存对细粒度级别的数据的缓存实现不好,比如:对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次都能查询最新的商品信息,此时如果使用mybatis的二级缓存就无法实现当一个商品变化时只刷新该商品的缓存信息而不刷新其它商品的信息。因为mybaits的二级缓存区域以mapper为单位划分,当一个商品信息变化会将所有商品信息的缓存数据全部清空。
解决此类问题需要在业务层根据需求对数据有针对性缓存。
SpringBoot整合Mybatis可通过以下设置二级缓存:
- #使全局的映射器启用或禁用缓存。
mybatis.configuration.cache-enabled=true - #全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载。
mybatis.configuration.lazy-loading-enabled=true - #当启用时,有延迟加载属性的对象在被调用时将会完全加载任意属性。否则,每种属性将会按需要加载。
mybatis.configuration.aggressive-lazy-loading=true - #是否允许单条sql 返回多个数据集 (取决于驱动的兼容性) default:true
mybatis.configuration.multiple-result-sets-enabled=true - #是否可以使用列的别名 (取决于驱动的兼容性) default:true
mybatis.configuration.use-column-label=true - #允许JDBC 生成主键。需要驱动器支持。如果设为了true,这个设置将强制使用被生成的主键,有一些驱动器不兼容不过仍然可以执行。 default:false
mybatis.configuration.use-generated-keys=true - #指定 MyBatis 如何自动映射 数据基表的列 NONE:不隐射\\u3000PARTIAL:部分 FULL:全部
mybatis.configuration.auto-mapping-behavior=partial - #这是默认的执行类型 (SIMPLE: 简单; REUSE: 执行器可能重复使用prepared statements语句;BATCH: 执行器可以重复执行语句和批量更新)
mybatis.configuration.default-executor-type=simple - #使用驼峰命名法转换字段。
mybatis.configuration.map-underscore-to-camel-case=true - #设置本地缓存范围 session:就会有数据的共享 statement:语句范围 (这样就不会有数据的共享 ) defalut:session
mybatis.configuration.local-cache-scope=session - #设置但JDBC类型为空时,某些驱动程序 要指定值,default:OTHER,插入空值时不需要指定类型
mybatis.configuration.jdbc-type-for-null=null - #如果数据为空的字段,则该字段省略不显示,可以通过添加配置文件,规定查询数据为空是则返回null。
mybatis.configuration.call-setters-on-nulls=true
比如,通过以下代码可以禁用MyBatis的二级缓存:
mybatis:
type-aliases-package: com.hc.domain
configuration:
map-underscore-to-camel-case: true
cache-enabled: false #禁用二级缓存
mapper-locations: mappers/*.xml
以上是关于mybatis缓存机制详解 #yyds干货盘点#的主要内容,如果未能解决你的问题,请参考以下文章
#yyds干货盘点# mybatis源码解读:cache包(缓存基本功能)