MyBatis缓存介绍:
1.MyBatis提供缓存机制分别有sqlseeion缓存(一级缓存)和sqlsessionFactory缓存(二级缓存);
2.二者区别在于作用域不一样;
3.缓冲区更新机制,当作用域(sqlseeion缓存/sqlsessionFactory缓存)进行 增/删/改 的时候,对应的作用域缓存会被清除;
一级缓存测试:
同一个sqlseeion 执行同一个select标签(调用SQL)时,第一次调用select标签会去数据库将数据缓存到缓冲区中并且返回数据结果,第二调用select标签是在缓冲区中获得数据结果,不同的sqlseeion 不共用缓存;
package com.gx.servlet;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.gx.dao.cacheMapper;
import com.gx.pojo.Account;
public class 缓存 {
public static void main(String[] args) throws IOException {
//数据库连接属性
InputStream resourceAsStream = Resources.getResourceAsStream("GlobalConfiguration.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
//作用域One
SqlSession openSessionOne = build.openSession();
//作用域Two
SqlSession openSessionTwo = build.openSession();
//作用域One----第一次调用selAll需要访问数据库
cacheMapper mapperOne = openSessionOne.getMapper(cacheMapper.class);
List<Account> selAllOne = mapperOne.selAll();
for (Account account : selAllOne) {
System.out.println("我是数据库的数据:"+account.toString());
}
//作用域One----第二次selAll调用直接调用缓存
System.out.println("第二次运行不需要去访问数据库");
cacheMapper mapperOne1 = openSessionOne.getMapper(cacheMapper.class);
List<Account> selAllOne1 = mapperOne1.selAll();
for (Account account : selAllOne1) {
System.out.println("我是缓冲区的数据:"+account.toString());
}
//作用域Two----同样调用selAll,但不是同一个SqlSession作用域,所以要重新访问数据库
cacheMapper mapper1 = openSessionTwo.getMapper(cacheMapper.class);
List<Account> selAll1 = mapper1.selAll();
for (Account account : selAll1) {
System.out.println(account.toString());
}
}
}
运行结果:
可以从运行结果中看到执行了两次查询sql语句,第二次不需要执行查询sql语句;
因为有缓存机制,可以大大降低对数据库的访问,都知道访问数据库是比较耗时的,这样不用重复访问数据库可以大大提升速度;
二级缓存测试:
sqlsessionFactory下的两个不相同的sqlseeion执行同一个select标签(调用SQL)时,也可以使用缓存的数据数据,如第一次调用需要去数据库访问,第二次就直接调用缓存;
开启二级缓存有两种方法:
第一种:加入cache 标签,并且设置读取属性
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.gx.dao.cacheMapper">
<!--开启二级缓存-->
<cache readOnly="true"></cache>
<select id="selAll" resultType="Account">
select * from Account
</select>
</mapper>
第二种:加入cache 标签,不加只读属性;但操作的类必须系列化,如 class Account implements Serializable{}
二级缓存测试:
package com.gx.servlet;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.gx.dao.cacheMapper;
import com.gx.pojo.Account;
public class 缓存 {
public static void main(String[] args) throws IOException {
//数据库连接属性
InputStream resourceAsStream = Resources.getResourceAsStream("GlobalConfiguration.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
//作用域One
SqlSession openSessionOne = build.openSession();
//作用域Two
SqlSession openSessionTwo = build.openSession();
//作用域One
cacheMapper mapperOne = openSessionOne.getMapper(cacheMapper.class);
List<Account> selAllOne = mapperOne.selAll();
for (Account account : selAllOne) {
System.out.println("我是数据库的数据:"+account.toString());
}
//必须关闭或者提交数据才会缓冲到缓冲区中
openSessionOne.close();
//openSessionOne.commit()
//作用域Two
cacheMapper mapperTwo = openSessionTwo.getMapper(cacheMapper.class);
List<Account> selAllTwo = mapperTwo.selAll();
for (Account account : selAllTwo) {
System.out.println(account.toString());
}
openSessionOne.close();
}
}
运行结果:
只执行了一次查询SQL语句,第二次获取缓存的数据不需要调用SQL;
说简单点就是:一级缓存只共享同一个sqlseeion的数据,二级缓存共享sqlsessionFactory下所有的sqlseeion的数据;
数据提取流程:
步骤一:先去缓冲区找是否存在statement
步骤二:返回结果
步骤三:如果没有缓存statement对象就到数据库获取数据
步骤四:数据库返回结果数据
步骤五:把数据库返回结果放到缓冲区中
补充标签常用属性:
<cache
eviction="FIFO" <!--回收策略为先进先出-->
flushInterval="60000" <!--自动刷新时间60s-->
size="512" <!--最多缓存512个引用对象-->
readOnly="true"/> <!--只读-->