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 }

     

  • 相关阅读:
    FZU 2098 刻苦的小芳(卡特兰数,动态规划)
    卡特兰数总结
    FZU 1064 教授的测试(卡特兰数,递归)
    HDU 4745 Two Rabbits(区间DP,最长非连续回文子串)
    Java 第十一届 蓝桥杯 省模拟赛 正整数的摆动序列
    Java 第十一届 蓝桥杯 省模拟赛 反倍数
    Java 第十一届 蓝桥杯 省模拟赛 反倍数
    Java 第十一届 蓝桥杯 省模拟赛 反倍数
    Java 第十一届 蓝桥杯 省模拟赛 凯撒密码加密
    Java 第十一届 蓝桥杯 省模拟赛 凯撒密码加密
  • 原文地址:https://www.cnblogs.com/bulrush/p/12549568.html
Copyright © 2011-2022 走看看