实体类
Student
@Data
@Table(name = "student")
public class StudentEntity implements Serializable {private static final long serialVersionUID = 1L;@Id@Column(name = "id")private Long id;@Column(name = "name")private String name;@Column(name = "class_id")private Long classId;@Transientprivate String className;}
Class
@Data
@Table(name = "class")
public class ClassEntity implements Serializable {private static final long serialVersionUID = 1L;@Id@Column(name = "id")private Long id;@Column(name = "name")private String name;}
表结构
CREATE TABLE `student` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(255) DEFAULT NULL,`class_id` int(11) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
CREATE TABLE `class` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(255) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
一级缓存
一级缓存是sqlSession
级别的,二级缓存是SqlSessionFactory
级别的
一级缓存-测试1
@Autowiredprivate SqlSessionFactory sqlSessionFactory;@Testpublic void t1() {SqlSession sqlSession = sqlSessionFactory.openSession();// 同一个sqlSession,同一个mapper实例,执行相同的查询语句StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);studentMapper.selectAll();studentMapper.selectAll();// 结论:只会出现1次sql语句,第二次查询走缓存}
一级缓存-测试2
@Testpublic void t2() {SqlSession sqlSession = sqlSessionFactory.openSession();// 同一个sqlSession,不同的mapper实例,执行相同的查询语句StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);studentMapper.selectAll();StudentMapper studentMapper2 = sqlSession.getMapper(StudentMapper.class);studentMapper2.selectAll();// 结论:只会出现1次sql语句,第二次查询走缓存}
一级缓存-测试3
@Testpublic void t3() {// 不同sqlSession,执行相同的查询语句SqlSession sqlSession = sqlSessionFactory.openSession();SqlSession sqlSession2 = sqlSessionFactory.openSession();StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);studentMapper.selectAll();StudentMapper studentMapper2 = sqlSession2.getMapper(StudentMapper.class);studentMapper2.selectAll();// 结论:出现2次sql语句,没有缓存效果}
一级缓存-测试4(update)
@Testpublic void t4() {SqlSession sqlSession = sqlSessionFactory.openSession();// 第一次查询StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);List<StudentEntity> list = studentMapper.selectAll();// 更新操作StudentEntity student = list.get(0);student.setName("修改学生姓名");studentMapper.updateByPrimaryKey(student);// 第二次查询studentMapper.selectAll();// 结论:第一次会出现sql语句,由于进行了更新操作,导致缓存失效,第二次查询也会重新查询sql}
一级缓存-测试5(update)
和测试4类似,但是update
的对象改为class
,看看是否会影响student
的查询
@Testpublic void t5() {SqlSession sqlSession = sqlSessionFactory.openSession();// 第一次查询studentStudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);List<StudentEntity> list = studentMapper.selectAll();// 更新classClassMapper classMapper = sqlSession.getMapper(ClassMapper.class);ClassEntity classx = classMapper.selectAll().get(0);classx.setName("修改班级姓名");classMapper.updateByPrimaryKey(classx);// 第二次查询studentstudentMapper.selectAll();// 结论:第一次会出现sql语句,由于进行了更新操作(即使不是同一个mapper实例),也会导致缓存失效,第二次查询也会重新查询sql}
一级缓存-测试6(springboot失效)
@Autowiredprivate StudentMapper studentMapper;@Testpublic void t6() {// 使用mybatis整合springboot后,直接查询2次studentMapper.selectAll();studentMapper.selectAll();// 结论:会出现2次sql查询,缓存失效,因为每一次sql语句的执行都是使用新的sqlSession}
二级缓存
一级缓存默认开启,二级缓存默认关闭
开启配置
mybatis:configuration:cache-enabled: true
给mapper添加<cache/>
,前面用的通用mapper的selectAll
方法,二级缓存一直没生效,这里重新手写一个查询方法getAll,再加上useCache
配置才行
<?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.tw.nr.network.dao.mapper.StudentMapper"><cache/><!--开启二级缓存--><!--获取学生列表--><select id="getAll" resultType="com.tw.nr.network.entity.StudentEntity" useCache="true">select * from student;</select><!--获取学生详细信息--><select id="getStudentDetail" resultType="com.tw.nr.network.entity.StudentEntity" useCache="true">SELECTa.`name`,b.`name` AS classNameFROMstudent aJOIN class b ON a.class_id = b.idwherea.id=#{id}</select></mapper>
<?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.tw.nr.network.dao.mapper.ClassMapper"><cache/><!--开启二级缓存--></mapper>
二级缓存-测试1
@Testpublic void t7() {// 不同sqlSession,执行相同的查询语句SqlSession sqlSession = sqlSessionFactory.openSession();SqlSession sqlSession2 = sqlSessionFactory.openSession();StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);studentMapper.getAll();sqlSession.commit();StudentMapper studentMapper2 = sqlSession2.getMapper(StudentMapper.class);studentMapper2.getAll();// 结论:只会查询1次sql语句,第二次查询走缓存}
二级缓存-测试2(脏数据)
二级缓存不适合多表查询,因为student
和class
处于不同的命名空间,在student
的命名空间执行了sqlA
的联表查询(student和class联表),进行了缓存,然后class
执行了更新,但这并不会刷新sqlA
的缓存,导致sqlA
还是读取到了脏数据
@Testpublic void t8() {SqlSession sqlSession = sqlSessionFactory.openSession();// 第一次查询学生的详细信息(联查了class表)StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);StudentEntity student = studentMapper.getStudentDetail(1L);System.out.println(student);sqlSession.commit();// 更新了class表ClassMapper classMapper = sqlSession.getMapper(ClassMapper.class);ClassEntity classx = classMapper.selectAll().get(0);classx.setName("班级1000");classMapper.updateByPrimaryKey(classx);sqlSession.commit();// 再次查询学生的详细信息student = studentMapper.getStudentDetail(1L);System.out.println(student);/*** 结论:读取到了脏数据,二级缓存不适合多表查询,因为student和class处于不同的命名空间,在student的命名空间执行了sqlA的联表查询(student和class联表),进行了缓存* 然后class执行了更新,但这并不会刷新sqlA的缓存,导致sqlA还是读取到了脏数据* */}