介绍
缓存,就是将经常访问的数据,放到内存中,减少对数据库的访问,提高查询速度。Mybatis中也有缓存的概念,分为一级缓存和二级缓存。
一级缓存
一级缓存是Mybatis中SqlSession对象的缓存。当我们执行查询以后,结果会存入到SqlSession为我们提供的一块区域中,该区域的结构是一个Map,当我们再次查询同样的数据,mybatis会先去Sqlsession中查询是否有,有的话直接拿出来用,没有再去查询数据库。
示例:
Mysql中建好表,对应的实体类也建好:
import java.util.Date;
public class Student {
private int id;
private int age;
private String name;
private Date birthday;
private int score;
//get和set方法省略...
}
Dao层的接口:
import java.io.Serializable;
public interface StudentMapper {
Student getById(Serializable id);
}
Dao层的xml:
<mapper namespace="com.gs.spring_boot_demo.mybatis.mapper.StudentMapper">
<select id="getById" resultType=
"com.gs.spring_boot_demo.mybatis.entity.Student">
select * from student where id = #{id}
</select>
</mapper>
测试类:
import com.gs.spring_boot_demo.mybatis.entity.Student;
import com.gs.spring_boot_demo.mybatis.mapper.StudentMapper;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class MybatisTest {
@Autowired
private StudentMapper mapper;
@Autowired
private SqlSessionFactory factory;
@Test
public void test() {
// 不能用这种方式,这种方式不会有一级缓存的
//Student student = mapper.getById(1);
//Student student1 = mapper.getById(1);
//System.out.println(student == student1);
SqlSession sqlSession = factory.openSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
Student student = mapper.getById(1);
Student student1 = mapper.getById(1);
System.out.println(student == student1);
}
}
看到控制台的输出:
查了2次id为1的数据,但只有1条发送sql的日志,并且2次查询的结果是同一个对象。说明一级缓存生效了。
清除一级缓存的方法也有很多,调用SqlSession对象的commit()、close()、clearCache()、增加、修改、删除时,就会删除一级缓存。
@Test
public void test() {
SqlSession sqlSession = factory.openSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
Student student = mapper.getById(1);
//commit()也能清除
//sqlSession.commit();
sqlSession.clearCache();
Student student1 = mapper.getById(1);
System.out.println(student == student1);
}
再次查看控制台的日志:
可以看到,因为删除了一级缓存,所以第二次的查询去发送sql查数据库了,2个查询结果也自然不是同一个对象。
二级缓存
一级缓存的前提条件是同一SqlSession对象,而二级缓存是跨SqlSession对象的,即多个SqlSession对象共享这一份缓存。当一级缓存关闭或提交后,一级缓存会转入到二级缓存,并且缓存的是数据而不是对象。
示例:
二级缓存默认未开启,首先开启它:
Dao层的xml中添加:
<cache/>
xml的select标签设置属性useCache:
<mapper namespace="com.gs.spring_boot_demo.mybatis.mapper.StudentMapper">
<cache/>
<select id="getById" resultType=
"com.gs.spring_boot_demo.mybatis.entity.Student" useCache="true">
select * from student where id = #{id}
</select>
</mapper>
开启二级缓存后,实体类Student要实现Serializable接口:
import java.io.Serializable;
import java.util.Date;
public class Student implements Serializable {
private int id;
private int age;
private String name;
private Date birthday;
private int score;
//get和set方法省略...
}
测试类:
@Test
public void test() {
SqlSession sqlSession = factory.openSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
Student student = mapper.getById(1);
//把一级缓存转入到二级缓存,同时清空一级缓存
sqlSession.commit();
//相同的SqlSession对象
Student student1 = mapper.getById(1);
System.out.println(student == student1);
//不同的SqlSession对象
SqlSession sqlSession1 = factory.openSession();
StudentMapper mapper1 = sqlSession1.getMapper(StudentMapper.class);
Student student2 = mapper1.getById(1);
System.out.println(student == student2);
}
看到控制台的日志:
getById(Serializable id)调用了3次,但是只有1条sql日志,后面的2次调用都是查的二级缓存,但对象不是同一个,所以说缓存的是数据而不是对象。