> 文档中心 > 【Mybatis从入门到实战教程】第七章 Mybatis 查询缓存详解

【Mybatis从入门到实战教程】第七章 Mybatis 查询缓存详解


七、Mybatis 查询缓存

    缓存:将数据临时存储在存储介质(内存,文件)中,关系型数据库的缓存目的就是为了减轻数据库的压力。
    
    数据库的数据实际是存储在硬盘中,如果我们程序需要用到数据,那么就需要频繁的从磁盘中读取数据,效率低,数据库压力大。我们可以把查询到的数据缓存起来,这样就减少了频繁操作磁盘数据,提高查询效率,减轻服务器压力。
    
    Mybatis提供了查询缓存,用于减轻数据库压力,提高数据库性能。但是在实际项目开发中,很少使用Mybatis的缓存机制,现在主流的缓存机制是redis。

7.1 什么是查询缓存

  • MyBatis提供查询缓存,用于减轻数据库压力,提高数据库性能;

  • MyBatis提供一级缓存,和二级缓存

  • 一级缓存是SqlSession级别的缓存。在操作数据库时需要构造SqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的SqlSession之间的缓存数据区域(HashMap)是互相不影响的;

  • 二级缓存是mapper级别的缓存,多个SqlSession去操作同一个mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的;

7.2 一级缓存

7.2.1 一级缓存工作原理

  • 第一次查询id为1的数据,先去找一级缓存中查找是否有id为1的数据,如果没有,从数据库中查询该数据,并将该数据存储到一级缓存中;

  • 第二次查询id为1的数据,也先去找一级缓存中查找是否有id为1的数据,缓存中有,直接从缓存中获取该数据,不再查询数据库;

  • 如果SqlSession去执行commit操作(执行插入、更新、删除),将清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的数据,避免脏读;

7.2.2 实体类

public class Person {    private Integer id;    private String personName;    private Integer personAge;    private String personAddress;    public Integer getId() { return id;    }    public void setId(Integer id) { this.id = id;    }    public String getPersonName() { return personName;    }    public void setPersonName(String personName) { this.personName = personName;    }    public Integer getPersonAge() { return personAge;    }    public void setPersonAge(Integer personAge) { this.personAge = personAge;    }    public String getPersonAddress() { return personAddress;    }    public void setPersonAddress(String personAddress) { this.personAddress = personAddress;    }    @Override    public String toString() { return "Person{" +  "id=" + id +  ", personName='" + personName + '\'' +  ", personAge=" + personAge +  ", personAddress='" + personAddress + '\'' +  '}';    }}

7.2.3 mapper接口

public interface PersonMapper {    Person selectById(Integer id);    List select();}

7.2.4 mapper文件

     select id,person_name,person_age,person_address from person where id=#{id}         select id,person_name,person_age,person_address from person    

7.2.5 测试

public class CacheTest {    @Test    public void testSqlSessionCache() { SqlSession sqlSession = MybatisUtil.getSession(); PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class); System.out.println("----------第一次使用id为1的person数据-----------"); Person p1 = personMapper.selectById(1); System.out.println(p1); /**  * 一级缓存自带缓存,不可不用的,缓存介质为内存  * commit()提交方法可以请求缓存  */ //sqlSession.commit(); System.out.println("----------第二次使用id为1的person数据-----------"); Person p2 = personMapper.selectById(1); System.out.println(p2); sqlSession.close();    }}

7.3 二级缓存

7.3.1 二级缓存工作原理

  • SqlSession1去查询id为1的数据,查询到后会将该数据存储到二级缓存中;

  • SqlSession2去查询id为1的数据,去缓存中找是否存在数据,如果存在直接从缓存中取出数据;

  • 如果SqlSession3去执行相同mapper下sql,执行commit提交,清空该mapper下的二级缓存区域的数据;

  • 二级缓存与一级缓存区别,二级缓存的范围更大,多个SqlSession可以共享一个Mapper的二级缓存区域;

  • 每个mapper有一个二级缓存区域,按namespace分;

  • 如果两个mapper的namespace如果相同,这两个mapper执行sql查询到数据将存在相同的二级缓存区域中;

7.3.2 开启二级缓存

在mybatis核心配置文件中配置:cacheEnabled

设置项 描述 允许值 默认值
cacheEnabled 对在此配置文件下的所有cache 进行全局性开/关设置 true \ false true
        

在映射文件中开启二缓存,mapper.xml下的SQL执行完成会存储到它的缓存区域HashMap。

          ...    

7.3.3 实体类

    二级缓存中存储数据的实体类必须实现可序列化接口java.io.Serializable。

public class Person implements Serializable {    }

7.3.4 二级缓存测试

@Testpublic void testMapperCache(){    /**     * 二级缓存,可插拔式缓存,缓存介质:内存+磁盘     */    SqlSession sqlSession1 = MybatisUtil.getSession();    PersonMapper personMapper1 = sqlSession1.getMapper(PersonMapper.class);    System.out.println("-------------第一次查询--------------");    Person p1 = personMapper1.selectById(2);    System.out.println(p1);    sqlSession1.close();    System.out.println("----------------sqlSession1关闭,建立sqlSession2连接-------------------");    SqlSession sqlSession2 = MybatisUtil.getSession();    PersonMapper personMapper2 = sqlSession2.getMapper(PersonMapper.class);    System.out.println("-------------第二次查询--------------");    Person p2 = personMapper2.selectById(2);    System.out.println(p2);    sqlSession2.close();}

7.3.5 useCache配置

    在statement中设置useCache="false"可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询。默认情况是true,即该sql使用二级缓存。

             select id,person_name,person_age,person_address from person where id=#{id}             select id,person_name,person_age,person_address from person    

测试:

@Testpublic void testMapperCache2() {    SqlSession sqlSession1 = MybatisUtil.getSession();    PersonMapper personMapper1 = sqlSession1.getMapper(PersonMapper.class);    System.out.println("-------------第一次查询--------------");    List list1 = personMapper1.select();    System.out.println(list1);    sqlSession1.close();    System.out.println("----------------sqlSession1关闭,建立sqlSession2连接-------------------");    SqlSession sqlSession2 = MybatisUtil.getSession();    PersonMapper personMapper2 = sqlSession2.getMapper(PersonMapper.class);    System.out.println("-------------第二次查询--------------");    List list2 = personMapper2.select();    System.out.println(list2);    sqlSession2.close();}