MyBatis具有非常强大的查询缓存特性,它可以方便地配置和定制。缓存可以进行全局的配置,也可以针对映射语句进行配置。MyBatis的缓存分为一级缓存和二级缓存,一级缓存指的是在session 内,session没有关闭时,执行同样的SQL语句会使用的缓存。如果参数改变,缓存就会失效。而二级缓存可以被所有的SqlSession共享,下面指的是对二级缓存的配置。
1.MyBatis的全局cache配置
全局的开关在MyBatis的配置文件中,默认是true。如果它配置成false,在Mapper XML中再配置支持cache也没有用。
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
2.在Mapper XML文件中开启二级缓存
在Mapper XML文件中设置缓存,默认情况下是没有开启缓存的。
要开启二级缓存,需要在SQL映射文件中添加一行:
<cache/>
它将采用默认的行为进行缓存。可以通过修改缓存元素的属性进行定制,如:
<cache eviction="FIFO" flushInterval="60000"
size="512" readOnly="true"/>
默认行为如下:
Ø 映射语句文件中的所有select语句的查询结果将会被缓存。
Ø 映射语句文件中的所有insert、update和delete语句会刷新缓存。
Ø 缓存会使用LeastRecently Used (LRU,最近很少使用的)算法来回收。
Ø 只在语句调用时刷新缓存。
Ø 缓存会存储查询返回的列表集合或对象的1024个引用。
Ø 读写缓存,意味着查到的对象不是共享的,调用者可以放心地使用和修改,不会受到其他调用者或线程所做的潜在修改的干扰。
属性及其描述如下表所示:
属性名称 | 描述 |
eviction | 可用资源的回收策略,主要包括以下几种: LRU:较少使用的、移除最长时间不被使用的对象。 FIFO(先进先出):按对象进入缓存的顺序将其移除。 SOFT(软引用):移除基于垃圾回收器状态和软引用规则的对象。 WEAK(弱引用):积极地移除基于垃圾收集器状态和弱引用规则的对象。默认为LRU |
flushInterval | 刷新间隔,可以被设置为任意的正整数,它们代表一个合理的毫秒形式的时间段。 默认情况下不设置,即没有刷新间隔,缓存仅在调用语句时刷新 |
size | 引用数目,可以被设置为任意正整数,要牢记缓存的对象数目和运行环境的可用内存资源数目。 默认值为1024 |
readOnly | 只读属性可以被设置为true或false。只读的缓存设置会给所有调用者返回缓存对象的相同实例。 因此这些对象不能被修改。此处提供了很重要的性能优势。 可读写的缓存会返回缓存对象的拷贝(通过序列化)。 这样较为缓慢,但比较安全,因此默认为false |
3.单独设置cache
在Mapper XML文件配置支持cache后,如果需要对个别查询进行调整,可以单独设置cache。
<selectid="SelectAll" resultType= "StudentEntity" useCache="true" >
select的useCache的默认值是true,一般情况下采用默认值。
4. 缓存演示案例
package com.obtk.test3;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.session.SqlSession;
import com.obtk.entitys.StudentEntity;
import com.obtk.utils.MybatisUtil;
public class TestCacheOne {
public static void main(String[] args) {
SqlSession session=null;
try {
//4.得到session
session=MybatisUtil.getSession();
//5.执行语句
List<StudentEntity> stuList=session.selectList("stu.selectByName", "王");
for(StudentEntity stu : stuList){
System.out.println(stu.getStuName()+","+stu.getGender());
}
System.out.println("============这是华丽的分割线=================");
//重新执行,只有一个sql,说明默认利用一级缓存
//MybatisUtil.closeSession();
//session=MybatisUtil.getSession();
stuList=session.selectList("stu.selectByName", "王");
for(StudentEntity stu : stuList){
System.out.println(stu.getStuName()+","+stu.getGender());
}
} catch (Exception e) {
e.printStackTrace();
}finally{
MybatisUtil.closeSession();
}
}
}
运行结果如下图所示:
只看到了一个sql语句输出,说明一级缓存起作用了
如果关闭session,再打开sesson,则运行结果如下图:
发现有两个sql输出,即查询了2次数据库。说明关闭了sesson之后,一级缓存失效了。
下面来看二级缓存的效果。
首先在核心配置文件里面开启二级缓存
=========================mybatis-config.xml====================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"mybatis-3-config.dtd">
<configuration>
<!-- 在核心配置文件里面开启二级缓存 -->
<settings>
<!-- 是否开启全局缓存 -->
<setting name="cacheEnabled" value="true"/>
<!-- 查询时,关闭关联对象即时加载以提高性能 -->
<setting name="lazyLoadingEnabled" value="false"/>
<!-- 对于未知的SQL查询,允许返回不同的结果集以达到通用的效果 -->
<setting name="multipleResultSetsEnabled" value="true"/>
<!-- 设置关联对象加载的形态,此处为按需加载字段(加载字段由SQL指 定),不会加载关联表的所有字段,以提高性能 -->
<setting name="aggressiveLazyLoading" value="true"/>
</settings>
</configuration>
然后在StudentMapper.xml中开启缓存。
<cache></cache>
==============================
package com.obtk.test3;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.session.SqlSession;
import com.obtk.entitys.StudentEntity;
import com.obtk.utils.MybatisUtil;
public class TestCacheTwo {
public static void main(String[] args) {
SqlSession session=null;
try {
//4.得到session
session=MybatisUtil.getSession();
//5.执行语句
List<StudentEntity> stuList=session.selectList("stu.selectByName", "王");
for(StudentEntity stu : stuList){
System.out.println(stu.getStuName()+","+stu.getGender());
}
//关闭session
MybatisUtil.closeSession();
session=MybatisUtil.getSession();
stuList=session.selectList("stu.selectByName", "王");
for(StudentEntity stu : stuList){
System.out.println(stu.getStuName()+","+stu.getGender());
}
} catch (Exception e) {
e.printStackTrace();
}finally{
MybatisUtil.closeSession();
}
}
}
这时候session关闭了重新再打开,运行效果如下:
发现只有一个sql输出,并且缓存命中了。