zoukankan      html  css  js  c++  java
  • Mybatis的一级缓存和二级缓存

    一:一级缓存:

    一级缓存在mybatis中默认是开启的并且是session级别,它的作用域为一次sqlSession会话。

     1 import com.smartdata.pms.PmsApplication;
     2 import com.smartdata.pms.entity.PmsProduct;
     3 import com.smartdata.pms.mapper.PmsProductMapper;
     4 import com.smartdata.pms.service.PmsProductService;
     5 import org.junit.Test;
     6 import org.junit.runner.RunWith;
     7 import org.springframework.beans.factory.annotation.Autowired;
     8 import org.springframework.boot.test.context.SpringBootTest;
     9 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    10 import org.springframework.transaction.annotation.Transactional;
    11 
    12 import java.util.concurrent.LinkedBlockingQueue;
    13 import java.util.concurrent.ThreadPoolExecutor;
    14 import java.util.concurrent.TimeUnit;
    15 
    16 /**
    17  * @ProjectName: smartdata
    18  * @Package: PACKAGE_NAME
    19  * @ClassName: CacheTest
    20  * @Author: heluwei
    21  * @Description: 缓存测试
    22  * @Date: 2020/3/21 18:34
    23  * @Version: 1.0
    24  */
    25 @RunWith(SpringJUnit4ClassRunner.class)
    26 @SpringBootTest(classes = PmsApplication.class)
    27 public class CacheTest{
    28     @Autowired
    29     PmsProductMapper pmsProductMapper;
    30     @Test
    31     @Transactional(rollbackFor = Throwable.class)
    32     public void testFistCache(){
    33         // 第一次查询,缓存到一级缓存
    34         System.out.println(pmsProductMapper.selectById(1));
    35         // 第二次查询,直接读取一级缓存
    36         System.out.println(pmsProductMapper.selectById(1));
    37 
    38     }
    39 }

    为什么开启事务
    由于使用了数据库连接池,默认每次查询完之后自动commite,这就导致两次查询使用的不是同一个sqlSessioin,根据一级缓存的原理,它将永远不会生效。
    当我们开启了事务,两次查询都在同一个sqlSession中,从而让第二次查询命中了一级缓存。读者可以自行关闭事务验证此结论。

     二:二级缓存

    默认情况下,mybatis打开了二级缓存,但它并未生效,因为二级缓存的作用域是namespace,所以还需要在Mapper.xml文件中配置一下才能使二级缓存生效

    使用Redis实现Mybatis的二级缓存。因为Mybatis的二级缓存存放在本地内存中。

    一:在yml文件中

    1 #配置mapper
    2 mybatis:
    3   #开启Mybatis的二级缓存
    4   configuration:
    5     cache-enabled: true

    二:自定义MybatisRedisCache 

    package com.smartdata.pms.cache;
    
    import lombok.extern.slf4j.Slf4j;
    import org.apache.ibatis.cache.Cache;
    import org.springframework.dao.DataAccessException;
    import org.springframework.data.redis.connection.RedisConnection;
    import org.springframework.data.redis.core.RedisCallback;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.core.ValueOperations;
    import org.springframework.util.CollectionUtils;
    
    import java.util.Set;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.locks.ReadWriteLock;
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    /**
     * @ProjectName: smartdata
     * @Package: com.smartdata.pms.cache
     * @ClassName: MyDefineRedisCache
     * @Author: heluwei
     * @Description: 使用Redis缓存Mybatis的二级缓存
     * @Date: 2020/3/22 22:56
     * @Version: 1.0
     */
    @Slf4j
    public class MybatisRedisCache implements Cache {
        // 读写锁
        private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);
    
        private static RedisTemplate redisTemplate;
    
    //    private RedisTemplate<String, Object> redisTemplate = SpringContextHolder.getBean("redisTemplate");
    
        private String id;
    
        public MybatisRedisCache(final String id) {
            if (id == null) {
                throw new IllegalArgumentException("Cache instances require an ID");
            }
            log.info("Redis Cache id " + id);
            this.id = id;
        }
    
        @Override
        public String getId() {
            return this.id;
        }
    
        @Override
        public void putObject(Object key, Object value) {
            if (value != null) {
                // 向Redis中添加数据,有效时间是2天
                redisTemplate.opsForValue().set(key.toString(), value, 2, TimeUnit.DAYS);
            }
        }
    
        @Override
        public Object getObject(Object key) {
            try {
                if (key != null) {
                    Object obj = redisTemplate.opsForValue().get(key.toString());
                    return obj;
                }
            } catch (Exception e) {
                log.error(e.getMessage());
            }
            return null;
        }
    
        @Override
        public Object removeObject(Object key) {
            try {
                if (key != null) {
                    redisTemplate.delete(key.toString());
                }
            } catch (Exception e) {
                log.error(e.getMessage());
            }
            return null;
        }
    
        @Override
        public void clear() {
            log.info("清空缓存");
            try {
                Set<String> keys = redisTemplate.keys("*:" + this.id + "*");
                if (!CollectionUtils.isEmpty(keys)) {
                    redisTemplate.delete(keys);
                }
            } catch (Exception e) {
                log.error(e.getMessage());
            }
        }
    
        @Override
        public int getSize() {
            Long size = (Long) redisTemplate.execute(new RedisCallback<Long>() {
                @Override
                public Long doInRedis(RedisConnection connection) throws DataAccessException {
                    return connection.dbSize();
                }
            });
            return size.intValue();
        }
    
        @Override
        public ReadWriteLock getReadWriteLock() {
            return this.readWriteLock;
        }
    
        public static void setRedisConnectionFactory(RedisTemplate redisTemplate) {
            MybatisRedisCache.redisTemplate = redisTemplate;
        }
    }

    在spring启动的时候,将redisTemplate注入到MybatisRedisCache类中

     1 package com.smartdata.pms.cache;
     2 
     3 import org.springframework.beans.factory.annotation.Autowired;
     4 import org.springframework.data.redis.core.RedisTemplate;
     5 import org.springframework.stereotype.Component;
     6 
     7 /**
     8  * @ProjectName: smartdata
     9  * @Package: com.smartdata.pms.cache
    10  * @ClassName: RedisCacheTransfer
    11  * @Author: heluwei
    12  * @Description:
    13  * @Date: 2020/3/22 23:19
    14  * @Version: 1.0
    15  */
    16 @Component
    17 public class RedisCacheTransfer {
    18 
    19     @Autowired
    20     public void setJedisConnectionFactory(RedisTemplate redisTemplate) {
    21         MybatisRedisCache.setRedisConnectionFactory(redisTemplate);
    22     }
    23 }

    在xml文件中加入<cache></cache>标签

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
     3 <mapper namespace="com.smartdata.pms.mapper.PmsProductMapper">
     4     <cache type="com.smartdata.pms.cache.MybatisRedisCache">
     5         <property name="eviction" value="LRU" />
     6         <property name="flushInterval" value="6000000" />
     7         <property name="size" value="1024" />
     8         <property name="readOnly" value="false" />
     9     </cache>
    10     <select id="getPmsProductPage"  resultType="com.smartdata.pms.entity.PmsProduct">
    11         select * from pms_product pp
    12         where 1=1
    13         and pp.del_flag = '0'
    14         <if test="pmsProduct.proNo != null and pmsProduct.proNo != ''">
    15             and pp.pro_no = #{pmsProduct.proNo}
    16         </if>
    17     </select>
    18 
    19     <select id="getOneById" parameterType="Long" resultType="String">
    20         select pro_no proNo from pms_product where 1=1 and pro_id = #{pId}
    21     </select>
    22 </mapper>

    缓存的只有在xml中的。利用Mybatis-plus,查询的接口没有效果。

    测试:

     1 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
     2 import com.smartdata.pms.PmsApplication;
     3 import com.smartdata.pms.mapper.PmsProductMapper;
     4 import org.junit.Test;
     5 import org.junit.runner.RunWith;
     6 import org.springframework.beans.factory.annotation.Autowired;
     7 import org.springframework.boot.test.context.SpringBootTest;
     8 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
     9 import org.springframework.transaction.annotation.Transactional;
    10 
    11 
    12 /**
    13  * @ProjectName: smartdata
    14  * @Package: PACKAGE_NAME
    15  * @ClassName: CacheTest
    16  * @Author: heluwei
    17  * @Description: 缓存测试
    18  * @Date: 2020/3/21 18:34
    19  * @Version: 1.0
    20  */
    21 @RunWith(SpringJUnit4ClassRunner.class)
    22 @SpringBootTest(classes = PmsApplication.class)
    23 public class CacheTest{
    24     @Autowired
    25     PmsProductMapper pmsProductMapper;
    26     /**
    27       * @Description: 一级缓存,因为使用了连接池,每次查询自动commit。
    28      */
    29     @Test
    30     @Transactional(rollbackFor = Throwable.class)
    31     public void testFistCache(){
    32         // 第一次查询,缓存到一级缓存
    33         System.out.println(pmsProductMapper.selectById(1));
    34         // 第二次查询,直接读取一级缓存
    35         System.out.println(pmsProductMapper.selectById(1));
    36     }
    37 
    38     /**
    39      * 测试二级缓存效果
    40      * 需要*Mapper.xml开启二级缓存
    41      **/
    42     @Test
    43     public void testSecondCache(){
    44         System.out.println(pmsProductMapper.getOneById(1L));
    45         System.out.println(pmsProductMapper.getOneById(1L));
    46         System.out.println(pmsProductMapper.getOneById(1L));
    47         System.out.println(pmsProductMapper.getOneById(1L));
    48         System.out.println(pmsProductMapper.selectById(1L));
    49         System.out.println(pmsProductMapper.selectById(1L));
    50         System.out.println(pmsProductMapper.selectById(1L));
    51         System.out.println(pmsProductMapper.selectById(1L));
    52     }
    53 }

     

  • 相关阅读:
    2019牛客暑期多校训练营(第二场)
    2019牛客暑期多校训练营(第一场)
    JOISC2014 挂饰("01"背包)
    UPC 2019年第二阶段我要变强个人训练赛第十六场
    UPC个人训练赛第十五场(AtCoder Grand Contest 031)
    Wannafly挑战赛15 C“出队”(约瑟夫环类问题)
    UVA 133“The Dole Queue”(循环报数处理技巧)
    洛谷P1169 [ZJOI2007]棋盘制作 悬线法 动态规划
    洛谷P1273 有线电视网 树上分组背包DP
    CF1097D Makoto and a Blackboard 质因数分解 DP
  • 原文地址:https://www.cnblogs.com/bulrush/p/12549568.html
Copyright © 2011-2022 走看看