一级缓存
一级缓存(也称为本地缓存)默认会启用,且不能被控制。
何时缓存
一级缓存如何起作用?
Mybatis的一级缓存存在于SqlSession的生命周期
中,在同一个SqlSession
中查询时,Mybatis会把执行的方法和参数通过算法生成缓存的键值,将键值和查询结果存入一个Map
对象中。
如果同一个SqlSession
中执行的方法和参数完全一致,那么通过算法会生成相同的键值,当Map缓存
对象中已存在该键值时,则会返回缓存中的对象。
可以通过在
<select>
属性中设置flushCache="true"
,每次查询都会清空当前的一级缓存,每次都会重新从数据库中查询数据。
何时更新缓存
任何的INSERT
、UPDATE
、DELETE
操作都会清空一级缓存。(尽管操作的是无关数据)
二级缓存
不同于一级缓存在SqlSession
生命周期中,二级缓存存在于SqlSessionFactory
的生命周期中,多个SqlSessionFactory
时,缓存数据不相通。
Mybatis的全局配置中,有一个参数
cacheEnabled
是二级缓存的开关。(默认为true)
二级缓存是和命名空间绑定的,即二级缓存需要配置在Mapper.xml映射文件
中,或者Mapper.java接口
中。
如何配置二级缓存
使用时,需要在Mapper.xml
中添加<cache />
元素即可。或Mapper.java接口
注解@CacheNamespace
。
默认的二级缓存效果:
- 映射语句文件中的所有
SELECT
语句将会被缓存。 - 映射语句文件中所有
INSERT
、UPDATE
、DELETE
语句会刷新缓存。 - 缓存会使用Least Recently Used(
LRU
,最近最少使用的)算法来回收。 - 根据时间表(如:no Flush Interval,没有刷新间隔),缓存不会以任何时间顺序来刷新。
- 缓存会存储
集合/对象
(无论查询方法返回什么类型的值)的1024个引用。 - 缓存会被视为
read/write
(可读/可写)的,意味着对象检索不是共享的
,而且可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。(线程安全)
可以修改配置:
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
或
@CacheNamespace(
eviction = FifoCache.class,
flushInterval = 60000,
size = 512,
readWrite = true
)
public interface RoleMapper{
}
该配置创建了一个FIFO缓存,每个60秒刷新一次,存储集合或对象的512个引用,而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改它们会导致冲突。
xml和java接口配置不能同时使用,因为它们相同的命名空间。
如何使用缓存
配置了二级缓存后,二级缓存就开始其作用了。
当调用了close()
方法关闭了SqlSession
时,SqlSession
才会保存查询数据到二级缓存中,在这之后二级缓存才有了缓存数据。
二级缓存适用场景
二级缓存虽然好处多,但并不是什么情况都可以用。
以下场景比较推荐:
- 以查询为主的应用,只有尽可能少的增、删、改。
- 绝大多数以单表操作存在时,由于很少存在互相关联的情况,因此不会出现脏数据。
- 可以按业务划分对表进行分组时,如关联的表比较少,可以通过参照缓存进行配置。
可读写与只读的缓存差别
配置了可读写的缓存时,Mybatis使用SerializedCache
(org.apache.ibatis.cache.decorators.SerializedCache)序列化缓存来实现可读写缓存类,并通过序列化和反序列化来保证通过缓存获取数据时,得到的是一个新的实例。
因为要使用序列化,这个被缓存的类要求实现
Serializable
接口。
如果配置为只读缓存,MyBatis就会使用Map
来存储缓存值,从缓存中获取到的对象就是同一个实例。
readOnly提供能很重要的性能优势。
- 只读的缓存只会给所有调用者返回缓存的相同实例。
- 可读写的缓存会通过序列化返回缓存对象的拷贝,这种方式会慢一些,但安全。
集成Redis缓存
官方提供了redis-cache
集成Redis数据库。
步骤:
- 添加依赖
mybatis-redis
。 - 配置redis,
src/main/resources
添加redis.properties
文件。
host=localhost
port=6379
connectionTimeout=5000
soTimeout=5000
password=
database=
clientName=
- 修改Mapper.xml。
<mapper namespace="com.demo.mapper.RoleMapper">
<cache type="org.mybatis.caches.redis.RedisCache" />
</mapper>
RedisCache在保存缓存数据和获取缓存数据时,使用java的序列化和反序列化,因此还需要保证被缓存的对象必须实现
Serializable
接口。