MyBatis缓存

缓存

MyBatis缓存机制,是为了加快sql语句的执行速度,将所查询过的语句存储在缓存区中,如果执行相同的语句可直接调用结果,不需要重复与数据库交互

MyBatis有两级缓存

  • 一级缓存:缓存区存在于sqlsession中,MyBatis始终开启这个缓存
  • 二级缓存:缓存区存在于namespace中,需要手动配置开启

一级缓存

通过调用同样的sql语句查询员工信息

    @Test
    public void FirstCacheTest() throws IOException {
        SqlSessionFactory sqlSessionFactory = MyBatisTest.getSqlSessionFactory();
        SqlSession sqlSession = sqlSessionFactory.openSession();
        try {
            EmployeeDao mapper = sqlSession.getMapper(EmployeeDao.class);
            Employee emp1 = mapper.getEmpById(1);
            System.out.println(emp1);
            //做一些其他事情
            Employee emp2 = mapper.getEmpById(1);
            System.out.println(emp2);
            System.out.println(emp1==emp2);
        }finally {

        }
    }

返回值及日志输出如下,可以看到只向数据库发送了一次请求

14:22:02.998 [main] DEBUG com.yellowstar.mybatis.dao.EmployeeDao.getEmpById - ==>  Preparing: select * from employee where id = ?
14:22:03.031 [main] DEBUG com.yellowstar.mybatis.dao.EmployeeDao.getEmpById - ==> Parameters: 1(Integer)
14:22:03.068 [main] DEBUG com.yellowstar.mybatis.dao.EmployeeDao.getEmpById - <==      Total: 1
Employee{id=1, lastName='Tomdam', gender='1', email='Tomdam@123.com'}
Employee{id=1, lastName='Tomdam', gender='1', email='Tomdam@123.com'}
true

什么情况下一级缓存会失效呢?

  • 两个不同的sqlsession发送的请求。自然是存储在两个不同的缓存区中,所以一级缓存会失效
  • sqlsession相同,但查询条件不同。
  • sqlsession相同,但两次操作之间执行了增删改操作。系统会不知道增删改操作有没有影响到已经缓存的数据,所以会再次查询
  • sqlsession相同,但两次操作直接调用了sqlsession.clearCache()方法,此方法效果是清空当前缓存区

二级缓存

二级缓存作用于namespace中,如果设置了二级缓存,当一级缓存的sqlsession关闭时,才会将一级缓存区的数据存储到二级缓存区。

设置二级缓存

  1. 全局配置文件中,设置开启二级缓存(默认是开启的,但还是建议显式的定义)

    <setting name="cacheEnabled" value="true"/>
    
  2. 在需要开启二级缓存的映射文件中配置cache标签,在这个标签中mybatis都有帮我们配置默认属性

    <mapper namespace="com.yellowstar.mybatis.dao.EmployeeDao">
        <cache/>
    </mapper>
    
  3. 让bean对象实现Serializable接口,为了将缓存数据取出执行反序列化操作,因为二级缓存数据存储介质多种多样,不一定只存在内存中,有可能存在硬盘中,如果我们要再取这个缓存的话,就需要反序列化了。

    public class Employee implements Serializable 
    

使用二级缓存

还是查询同一个员工信息,但使用两个不同的sqlsession来查询

    @Test
    public void SecondCacheTest() throws IOException {
        SqlSessionFactory sqlSessionFactory = MyBatisTest.getSqlSessionFactory();
        SqlSession sqlSession1 = sqlSessionFactory.openSession();
        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        try {
            EmployeeDao mapper1 = sqlSession1.getMapper(EmployeeDao.class);
            EmployeeDao mapper2 = sqlSession2.getMapper(EmployeeDao.class);
            Employee emp1 = mapper1.getEmpById(1);
            System.out.println(emp1);
            sqlSession1.close();
            //做一些其他事情
            Employee emp2 = mapper2.getEmpById(1);
            System.out.println(emp2);
            System.out.println(emp1==emp2);
            sqlSession2.close();
        }finally {

        }
    }

以下是输出信息及日志,注意倒数第四行,Cache Hit Ratio从缓存区中取得

14:46:34.682 [main] DEBUG com.yellowstar.mybatis.dao.EmployeeDao.getEmpById - ==>  Preparing: select * from employee where id = ?
14:46:34.709 [main] DEBUG com.yellowstar.mybatis.dao.EmployeeDao.getEmpById - ==> Parameters: 1(Integer)
14:46:34.745 [main] DEBUG com.yellowstar.mybatis.dao.EmployeeDao.getEmpById - <==      Total: 1
Employee{id=1, lastName='Tomdam', gender='1', email='Tomdam@123.com'}
14:46:34.750 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction - Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5d20e46]
14:46:34.751 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5d20e46]
14:46:34.751 [main] DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource - Returned connection 97652294 to pool.
14:46:34.752 [main] WARN org.apache.ibatis.io.SerialFilterChecker - As you are using functionality that deserializes object streams, it is recommended to define the JEP-290 serial filter. Please refer to https://docs.oracle.com/pls/topic/lookup?ctx=javase15&id=GUID-8296D8E8-2B93-4B9A-856E-0A65AF9B8C66
14:46:34.755 [main] DEBUG com.yellowstar.mybatis.dao.EmployeeDao - Cache Hit Ratio [com.yellowstar.mybatis.dao.EmployeeDao]: 0.5
Employee{id=1, lastName='Tomdam', gender='1', email='Tomdam@123.com'}
false

关于缓存的一些相关配置

  • cacheEnabled设置为false,二级缓存失效但不影响一级缓存

  • 每个select标签中都有一个useCache属性,默认为true,将他设置为false。二级缓存失效,但不影响一级缓存

        <select id="getEmpById" resultType="com.yellowstar.mybatis.bean.Employee" useCache="false">
            select * from employee where id = #{id}
        </select>
    
  • 执行完增删改操作后,都会清除缓存

  • sqlsession.clearCache(),只会清楚一级缓存

  • 设置全局配置文件中localCacheScope为STATEMENT,禁用一级缓存

整合第三方缓存ehcache

  1. 在pom.xml文件中导入ehcache依赖

    <dependency>
         <groupId>org.mybatis.caches</groupId>
         <artifactId>mybatis-ehcache</artifactId>
         <version>1.2.1</version>
    </dependency>
    
  2. 设置映射文件的cache标签中的type属性

    <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
    
  3. 设置ehcache配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
     <!-- 磁盘保存路径 -->
     <diskStore path="D:\44\ehcache" />
     
     <defaultCache 
       maxElementsInMemory="1000"
       maxElementsOnDisk="10000000"
       eternal="false" 
       overflowToDisk="true" 
       timeToIdleSeconds="120"
       timeToLiveSeconds="120" 
       diskExpiryThreadIntervalSeconds="120"
       memoryStoreEvictionPolicy="LRU">
     </defaultCache>
    </ehcache>
     
    <!-- 
    属性说明:
    l diskStore:指定数据在磁盘中的存储位置。
    l defaultCache:当借助CacheManager.add("demoCache")创建Cache时,EhCache便会采用<defalutCache/>指定的的管理策略
     
    以下属性是必须的:
    l maxElementsInMemory - 在内存中缓存的element的最大数目 
    l maxElementsOnDisk - 在磁盘上缓存的element的最大数目,若是0表示无穷大
    l eternal - 设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断
    l overflowToDisk - 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上
     
    以下属性是可选的:
    l timeToIdleSeconds - 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时,这些数据便会删除,默认值是0,也就是可闲置时间无穷大
    l timeToLiveSeconds - 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大
     diskSpoolBufferSizeMB 这个参数设置DiskStore(磁盘缓存)的缓存区大小.默认是30MB.每个Cache都应该有自己的一个缓冲区.
    l diskPersistent - 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。
    l diskExpiryThreadIntervalSeconds - 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s,相应的线程会进行一次EhCache中数据的清理工作
    l memoryStoreEvictionPolicy - 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出)
     -->
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值