缓存
MyBatis 具有缓存功能,可以将 select 语句进行缓存,下一次调用相同的 sql 语句就可以直接返回结果,减少数据库访问。MyBatis 的缓存分为一级缓存和二级缓存
一级缓存
默认情况下 MyBatis 使用一级缓存,该缓存无法关闭
缓存生命周期
一级缓存的生命周期就是从一个 sqlSession 创建到 sqlSession.close()
为止,事实上, 一级缓存就保存在 sqlSession 实例中,具体在其 localCache 字段内,以哈希表的形式保存
在执行 sqlSession.close()
后,localCache 就会被设为 null
缓存刷新
-
当执行数据库修改操作(insert,update,delete等)后,缓存会失效
System.out.println(mapper.selectById(1)); System.out.println(mapper.selectById(1)); System.out.println("=================="); mapper.update(new User(1,"user","3214")); System.out.println("=================="); System.out.println(mapper.selectById(1));
通过日志我们可以清楚地看到
==> Preparing: select id,name,password from user where id=? ==> Parameters: 1(Integer) <== Columns: id, name, password <== Row: 1, user, 134 <== Total: 1 User{id=1, name='user', password='134'} User{id=1, name='user', password='134'} // 直接返回缓存 ================== ==> Preparing: update user set name=?,password=? where id=? ==> Parameters: user(String), 3214(String), 1(Integer) <== Updates: 1 ================== ==> Preparing: select id,name,password from user where id=? // 缓存失效,重新查询 ==> Parameters: 1(Integer) <== Columns: id, name, password <== Row: 1, user, 3214 <== Total: 1 User{id=1, name='user', password='3214'}
-
手动清理缓存
通过 sqlSession 的
clearCache()
方法可以手动刷新缓存System.out.println(mapper.selectById(1)); sqlSession.clearCache(); System.out.println(mapper.selectById(1));
==> Preparing: select id,name,password from user where id=? ==> Parameters: 1(Integer) <== Columns: id, name, password <== Row: 1, user, 134 <== Total: 1 User{id=1, name='user', password='134'} ==> Preparing: select id,name,password from user where id=? ==> Parameters: 1(Integer) <== Columns: id, name, password <== Row: 1, user, 134 <== Total: 1 User{id=1, name='user', password='134'}
二级缓存
一级缓存只作用于 Session 周期内,如果想要全局缓存就需要开启 MyBatis 的二级缓存
开启二级缓存很简单,只需要在想要缓存的映射语句所在的映射文件中添加一行:
<cache/>
另外,缓存结果集对应的对象需要实现 Serializable
接口,不然可能出错
cache
标签还可以添加属性以设置缓存的行为,包括:
- eviction:清除缓存的策略,主要有 LRU(最近最少使用)和 FIFO(先进先出)等,默认为 LRU
- flushInterval:缓存刷新间隔,默认为不设置,即只在调用语句时刷新
- size:缓存保存的引用个数,默认为 1024
- readOnly:只读,为 true 时缓存会返回缓存对象的相同实例,因此不能修改。为 false 时缓存会返回缓存对象的拷贝,速度较慢但是更安全,默认为 false。返回对象拷贝依赖序列化,因此此时的对象必须实现
Serializable
接口,这也是上文提到不实现Serializable
可能出错的原因,而如果 readOnly 为 true 就不一定要实现Serializable
接口
示例:
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
参考
mybatis一级缓存二级缓存 - 寻找风口的猪 - 博客园 (cnblogs.com)