一、概述
像大多数的持久化框架一样,Mybatis 也提供了缓存策略,通过缓存策略来减少数据库的查询次数,从而提高性能。Mybatis 中缓存分为一级缓存,二级缓存。
二、一级缓存
一级缓存是 SqlSession 级别的缓存,只要 SqlSession 没有 flush 或 close,它就存在。
证明一级缓存的存在:
1.编写持久层接口
/**
* 根据id查询用户信息
* @param userId
* @return
*/
User findUserById(Integer userId);
2.编写持久层映射文件 userMapper.xml
<mapper namespace="com.itheima.dao.IUserDao">
<!-- 根据 id 查询 --> <select id="findById" resultType="UsEr" parameterType="int" useCache="true">
select * from user where id = #{uid}
</select>
</mapper>
3.编写测试方法
import com.mrhan.dao.IUserDao;
import com.mrhan.entity.User;
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 org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
public class UserTest {
private InputStream in;
private SqlSessionFactory factory;
private SqlSession session;
private IUserDao userDao;
@Before
public void init() throws Exception {
//1.读取配置文件
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.构建者对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//3.创建SqlSession工厂对象
factory = builder.build(in);
//4.创建SqlSession对象
session = factory.openSession(true);
//5.创建Dao代理对象
userDao = session.getMapper(IUserDao.class);
}
@After
public void destroy() throws Exception{
//session.commit();
//7.释放资源
session.close();
in.close();
}
@Test
public void testFindById(){
//6.查询
User user = userDao.findUserById(1);
System.out.println("第一次查询的用户:"+user);
User user2 = userDao.findUserById(1);
System.out.println("第二次查询的用户:"+user2);
}
4.测试结果如下:
可以看到,虽然上述代码查询了两次,但最后只执行了一次数据库操作,
这就是Mybatis一级缓存起作用了,第二次查询并没有通过sql语句从数据库中查询数据,而是从一级缓存中查询
5.一级缓存分析:
第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据库查询,并将其存储到一级缓存中
如果sqlsession去执行commit(插入更新删除时)
清空sqlsession一级缓存,这样做的目的是为了让缓存 中存储的是最新的消息 避免藏独
第二次发起查询,如果缓存中有 则直接从缓存中获取用户信息
三、Mybatis二级缓存
二级缓存是mapper 映射级别的缓存 多个SqlSession 去操作同一个mapper映射的sql语句
多个Sqlsession可以共用二级缓存 二级缓存是跨SqlSession的
- 在主配置文件mybatisConfig.xml中开启二级缓存
<settings>
<!-- 开启二级缓存的支持 --> <setting name="cacheEnabled" value="true"/>
</settings>
因为 cacheEnabled 的取值默认就为 true,所以这一步可以省略不配置。为 true 代表开启二级缓存;为false 代表不开启二级缓存。
2.配置Mapper映射文件
<cache>标签表示当前这个 mapper 映射将使用二级缓存,区分的标准就看 mapper 的 namespace 值。
<?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.itheima.dao.IUserDao">
<!-- 开启二级缓存的支持 -->
<cache></cache>
</mapper>
<!-- 根据 id 查询 --> <select id="findById" resultType="user" parameterType="int" useCache="true">
select * from user where id = #{uid}
</select> 将 UserDao.xml 映射文件中的<select>标签中设置 useCache=”true”代表当前这个 statement 要使用
二级缓存,如果不使用二级缓存可以设置为 false。
注意:针对每次查询都需要最新的数据 sql,要设置成 useCache=false,禁用二级缓存
3、二级缓存测试
@Before//用于在测试方法执行之前执行
public void init()throws Exception{
//1.读取配置文件,生成字节输入流
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.获取 SqlSessionFactory
factory = new SqlSessionFactoryBuilder().build(in);
}
@After//用于在测试方法执行之后执行
public void destroy()throws Exception{
in.close();
}
@Test
public void testFirstLevelCache(){
SqlSession sqlSession1 = factory.openSession();
IUserDao dao1 = sqlSession1.getMapper(IUserDao.class);
User user1 = dao1.findById(1);
System.out.println(user1);
sqlSession1.close();//一级缓存消失
SqlSession sqlSession2 = factory.openSession();
IUserDao dao2 = sqlSession2.getMapper(IUserDao.class);
User user2 = dao2.findById(1);
System.out.println(user2);
sqlSession2.close();
System.out.println(user1 == user2);
}
经过测试,我们发现执行了两次查询,并且在执行第一次查询后,我们关闭了以及缓存,再去执行第二次查询时,比我们发现并没有对数据库进行sql查询 所以此时的数据只能来自于我们所说的二级缓存