Mybatis的缓存

  • 在mybatis中提供了一种缓存机制,内存中有一块区域用来存放从数据库中查询的结果。当下次再执行相同的查询语句时,就不需要通过IO的方式从数据库中取数据(数据库中的数据实际上是存放在硬盘文件中),而是直接从缓存中取数据。一方面减少了IO操作次数,另一方面不再执行繁琐的查询算法,提高了查询效率。
  • 缓存机制是计算机中优化性能的一种重要手段。比如计算机系统中cache,java中的字符串常量池,整数常量池(-127-128),线程池、连接池等。都是缓存机制的应用
  • mybatis缓存包括:一级缓存(将查询的结果存储到SqlSession中)、二级缓存(将查询的结果存储到SqlSessionFactory中)或者集成第三方的缓存
  • mybatis的缓存机制只针对DQL语句(select),目的是提高查询效率
一级缓存
  • 一级缓存是默认开启的,不需要配置

  • 如果在同一个SqlSession对象执行相同的select语句,就会使用缓存机制,只在第一次执行select语句,其余语句不会执行,而是直接从缓存中取出结果返回。

  • 当SqlSession对象不同或者查询条件不同时,不会使用缓存机制

  • 一级缓存失效的条件

    1. 调用SqlSession的clearCache方法,进行手动清空缓存
    2. 只要执行insert、delete或update语句都会使一级缓存清空,即使这些语句是对另一张表的操作
  •   @Test
        public void testSelectById(){
            SqlSession sqlSession = SqlSessionUtil.getSqlSession();
            CarMapper mapper = sqlSession.getMapper(CarMapper.class);
      
            Car car1 = mapper.selectById(12L);
            System.out.println(car1);
            //sqlSession.clearCache();
            Car car2 = mapper.selectById(12L);
            System.out.println(car2);
            sqlSession.close();
        }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54

    * Preparing: select * from t_car where id = ?

    ##### 二级缓存

    * 二级缓存的作用范围为整个SqlSessionFactory(一个SqlSessionFactory对应一个数据库)

    * 如何使用二级缓存

    1. 在mybatis核心配置文件的settings标签中开启二级缓存机制,不过由于mybatis中默认开启二级缓存,所以不需要配置
    2. 在需要使用二级缓存的SqlMapper.xml文件中添加<cache/>标签
    3. 使用二级缓存的实体类必须可序列化,即实现java.io.Serializable接口
    4. 只有当SqlSession对象关闭或提交后,一级缓存中的数据才会写入二级缓存中,二级缓存才会生效

    * 一级缓存的优先级高于二级缓存

    * 二级缓存失效的条件

    * 只要执行insert、delete或update语句都会使一级缓存清空,即使这些语句是对另一张表的操作

    * 二级缓存的相关配置

    * 在cache标签中有很多属性

    * eviction:指定从缓存中移除某个对象的淘汰算法,默认使用LRU策略

    * LRU:least recently used,最近使用次数少的对象,优先淘汰在间隔时间内使用频率最低的对象
    * FIFO:first in first out,先进入缓存中的对象先被淘汰
    * SOFT:优先淘汰软引用指向的对象,与JVM的垃圾回收算法相关
    * WEAK:优先淘汰弱引用指向的对象,与JVM的垃圾回收算法相关

    * flushinterval:设置二级缓存的刷新间隔。默认不刷新

    * readonly:

    a. 值为true时,多条相同sql语句返回的对象是同一个,性能好,但有线程安全问题

    b. 值为false时,多条相同sql语句返回的对象是副本对象,调用了clone方法,线程安全但性能一般

    * size:设置缓存中可以存放对象的最大数量,默认值为1024

    * ```java
    public void testSelectByIdWithDifSqlS() throws Exception{
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
    SqlSession sqlSession1 = sqlSessionFactory.openSession();
    SqlSession sqlSession2 = sqlSessionFactory.openSession();
    CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);
    CarMapper mapper2 = sqlSession2.getMapper(CarMapper.class);
    Car car1 = mapper1.selectById(12L);
    System.out.println(car1);
    sqlSession1.close();
    Car car2 = mapper2.selectById(12L);
    System.out.println(car2);
    }
  • Preparing: select * from t_car where id = ?

集成第三方的缓存
  • 以Ehcache三方缓存器为例

  • 这种第三方的缓存器可以替代mybatis中的二级缓存,无法替代一级缓存

  • 使用步骤

    1. 引入Ehcache依赖

      • <dependency>
            <groupId>org.mybatis.caches</groupId>
            <artifactId>mybatis-ehcache</artifactId>
            <version>1.2.3</version>
        </dependency>
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34

        2. 在mybatis的根路径下新建ehcache.xml文件,并配置以下信息

        * ```xml
        <?xml version="1.0" encoding="UTF-8" ?>
        <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
        updateCheck="false">

        <defaultCache
        eternal="false"
        maxElementsInMemory="10000"
        overflowToDisk="false"
        diskPersistent="false"
        timeToLiveSeconds="3600"
        timeToIdleSeconds="0"
        diskExpiryThreadIntervalSeconds="120"
        memoryStoreEvictionPolicy="LRU"/>

        <cache
        name="user"
        eternal="false"
        maxElementsInMemory="10000"
        overflowToDisk="false"
        diskPersistent="false"
        timeToLiveSeconds="3600"
        timeToIdleSeconds="0"
        diskExpiryThreadIntervalSeconds="120"
        memoryStoreEvictionPolicy="LRU"/>

        <!-- 存储到磁盘时的路径-->
        <diskStore path="/Users/wuhanxue/Downloads/ehcache" />

        </ehcache>
    2. 修改cache标签,添加type属性

      • <cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>