• SpringBoot+MyBatis+Redis(二级缓存)


    应用场景:
    保存大数据量,避免重复请求。

    一、添加Maven依赖

    <!-- SpringBoot Boot Redis -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>

    二、编写Redis相关类

    RedisService.java

    import java.util.Collection;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    import java.util.concurrent.TimeUnit;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.HashOperations;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.core.ValueOperations;
    import org.springframework.stereotype.Component;
    
    @SuppressWarnings(value = { "unchecked", "rawtypes" })
    @Component
    public class RedisService
    {
        @Autowired
        public RedisTemplate redisTemplate;
    
        /**
         * 缓存基本的对象,Integer、String、实体类等
         *
         * @param key 缓存的键值
         * @param value 缓存的值
         */
        public <T> void setCacheObject(final String key, final T value)
        {
            redisTemplate.opsForValue().set(key, value);
        }
    
        /**
         * 缓存基本的对象,Integer、String、实体类等
         *
         * @param key 缓存的键值
         * @param value 缓存的值
         * @param timeout 时间
         * @param timeUnit 时间颗粒度
         */
        public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit)
        {
            redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
        }
    
        /**
         * 设置有效时间
         *
         * @param key Redis键
         * @param timeout 超时时间
         * @return true=设置成功;false=设置失败
         */
        public boolean expire(final String key, final long timeout)
        {
            return expire(key, timeout, TimeUnit.SECONDS);
        }
    
        /**
         * 设置有效时间
         *
         * @param key Redis键
         * @param timeout 超时时间
         * @param unit 时间单位
         * @return true=设置成功;false=设置失败
         */
        public boolean expire(final String key, final long timeout, final TimeUnit unit)
        {
            return redisTemplate.expire(key, timeout, unit);
        }
    
        /**
         * 获得缓存的基本对象。
         *
         * @param key 缓存键值
         * @return 缓存键值对应的数据
         */
        public <T> T getCacheObject(final String key)
        {
            ValueOperations<String, T> operation = redisTemplate.opsForValue();
            return operation.get(key);
        }
    
        /**
         * 删除单个对象
         *
         * @param key
         */
        public boolean deleteObject(final String key)
        {
            return redisTemplate.delete(key);
        }
    
        /**
         * 删除集合对象
         *
         * @param collection 多个对象
         * @return
         */
        public long deleteObject(final Collection collection)
        {
            return redisTemplate.delete(collection);
        }
    
        /**
         * 缓存List数据
         *
         * @param key 缓存的键值
         * @param dataList 待缓存的List数据
         * @return 缓存的对象
         */
        public <T> long setCacheList(final String key, final List<T> dataList)
        {
            Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
            return count == null ? 0 : count;
        }
    
        /**
         * 获得缓存的list对象
         *
         * @param key 缓存的键值
         * @return 缓存键值对应的数据
         */
        public <T> List<T> getCacheList(final String key)
        {
            return redisTemplate.opsForList().range(key, 0, -1);
        }
    
        /**
         * 缓存Set
         *
         * @param key 缓存键值
         * @param dataSet 缓存的数据
         * @return 缓存数据的对象
         */
        public <T> long setCacheSet(final String key, final Set<T> dataSet)
        {
            Long count = redisTemplate.opsForSet().add(key, dataSet);
            return count == null ? 0 : count;
        }
    
        /**
         * 获得缓存的set
         *
         * @param key
         * @return
         */
        public <T> Set<T> getCacheSet(final String key)
        {
            return redisTemplate.opsForSet().members(key);
        }
    
        /**
         * 缓存Map
         *
         * @param key
         * @param dataMap
         */
        public <T> void setCacheMap(final String key, final Map<String, T> dataMap)
        {
            if (dataMap != null) {
                redisTemplate.opsForHash().putAll(key, dataMap);
            }
        }
    
        /**
         * 获得缓存的Map
         *
         * @param key
         * @return
         */
        public <T> Map<String, T> getCacheMap(final String key)
        {
            return redisTemplate.opsForHash().entries(key);
        }
    
        /**
         * 往Hash中存入数据
         *
         * @param key Redis键
         * @param hKey Hash键
         * @param value 值
         */
        public <T> void setCacheMapValue(final String key, final String hKey, final T value)
        {
            redisTemplate.opsForHash().put(key, hKey, value);
        }
    
        /**
         * 获取Hash中的数据
         *
         * @param key Redis键
         * @param hKey Hash键
         * @return Hash中的对象
         */
        public <T> T getCacheMapValue(final String key, final String hKey)
        {
            HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
            return opsForHash.get(key, hKey);
        }
    
        /**
         * 获取多个Hash中的数据
         *
         * @param key Redis键
         * @param hKeys Hash键集合
         * @return Hash对象集合
         */
        public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys)
        {
            return redisTemplate.opsForHash().multiGet(key, hKeys);
        }
    
        /**
         * 获得缓存的基本对象列表
         * 
         * @param pattern 字符串前缀
         * @return 对象列表
         */
        public Collection<String> keys(final String pattern)
        {
            return redisTemplate.keys(pattern);
        }
    }

    RedisConfig.java

    import org.springframework.cache.annotation.CachingConfigurerSupport;
    import org.springframework.cache.annotation.EnableCaching;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.connection.RedisConnectionFactory;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.serializer.StringRedisSerializer;
    import com.fasterxml.jackson.annotation.JsonAutoDetect;
    import com.fasterxml.jackson.annotation.PropertyAccessor;
    import com.fasterxml.jackson.databind.ObjectMapper;
    @Configuration
    @EnableCaching
    public class RedisConfig extends CachingConfigurerSupport
    {
        @Bean
        @SuppressWarnings(value = { "unchecked", "rawtypes", "deprecation" })
        public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory)
        {
            RedisTemplate<Object, Object> template = new RedisTemplate<>();
            template.setConnectionFactory(connectionFactory);
    
            FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class);
    
            ObjectMapper mapper = new ObjectMapper();
            mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
            mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
            serializer.setObjectMapper(mapper);
    
            template.setValueSerializer(serializer);
            // 使用StringRedisSerializer来序列化和反序列化redis的key值
            template.setKeySerializer(new StringRedisSerializer());
            template.afterPropertiesSet();
            return template;
        }
    }

    RedisCache.java

    import org.apache.ibatis.cache.Cache;
    import org.springframework.data.redis.core.RedisCallback;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.core.ValueOperations;
    
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.locks.ReadWriteLock;
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    public class RedisCache implements Cache {
        private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
        private final String id;
        private RedisTemplate redisTemplate;
        //redis过期时间
        private static final long EXPIRE_TIME_IN_MINUTES = 30;
    
        public RedisCache(String id) {
            if (id == null) {
                throw new IllegalArgumentException("Cache instance required an ID");
            }
            this.id = id;
        }
    
        @Override
        public String getId() {
            return id;
        }
    
        /**
         * Put query result to redis
         *
         * @Param key
         * @Param value
         */
        @Override
        public void putObject(Object key, Object value) {
            RedisTemplate redisTemplate = getRedisTemplate();
            ValueOperations opsForValue = redisTemplate.opsForValue();
            System.out.println(key + ": key");
            System.out.println(key.toString() + ": key.toString()");
            System.out.println(value + ": value");
            System.out.println(value.toString() + ": value.toString()");
            opsForValue.set(key.toString(), value, EXPIRE_TIME_IN_MINUTES, TimeUnit.MINUTES);
            System.out.println("结果成功放入缓存 and " + "key = " + "
    " + key + "value = " + value);
            System.out.println(opsForValue.get(key.toString()));
        }
    
        /**
         * Get cached query result to redis
         *
         * @Param key
         * @Return
         */
        @Override
        public Object getObject(Object key) {
            RedisTemplate redisTemplate = getRedisTemplate();
    //        redisTemplate.setHashValueSerializer(new StringRedisSerializer());
            ValueOperations opsForValue = redisTemplate.opsForValue();
            System.out.println("结果从缓存中获取");
            return opsForValue.get(key.toString());
        }
    
        /**
         * Remove cached query result to redis
         *
         * @Param key
         * @Return
         */
        @Override
        public Object removeObject(Object key) {
            RedisTemplate redisTemplate = getRedisTemplate();
            redisTemplate.delete(key);
            System.out.println("从缓存中删除");
            return null;
        }
    
        /**
         * Clear this cache instance
         */
        @Override
        public void clear() {
            RedisTemplate redisTemplate = getRedisTemplate();
            redisTemplate.execute((RedisCallback) connection -> {
                connection.flushDb();
                return null;
            });
            System.out.println("清空缓存");
        }
    
        @Override
        public int getSize() {
            Long size = (Long) redisTemplate.execute((RedisCallback) connection -> connection.dbSize());
            return size.intValue();
        }
    
        @Override
        public ReadWriteLock getReadWriteLock() {
            return readWriteLock;
        }
    
        private RedisTemplate getRedisTemplate() {
            if (redisTemplate == null) {
                redisTemplate = ApplicationContextHolder.getBean("redisTemplate");
            }
            return redisTemplate;
        }
    }

    三、yml配置redis

    spring:
      redis:
        host: localhost
        port: 6379
        password:

    四、在DAO类添加该注解

    @CacheNamespace(implementation = RedisCache.class)

    五、实现类或者在Controller加如下代码,键值对保存对应的数据

    @Autowired
    private RedisService redisService;

    六、如何确保Redis数据实时更新

    我研究了下,通常如下:
    1.先删缓存,再更新数据库
    2.先写数据库,再删缓存
    参考:
    Redis缓存如何保证一致性

    补充:
    Redis 和 Mysql 数据库数据如何保持一致性

  • 相关阅读:
    idea自定义servlet模板
    jsp基础-指令,内置对象,动作,EL表达式,JSTL技术
    cookie和session
    HttpServletRequest
    IO字符流
    IO字节流
    递归
    File 类
    JDBC数据库连接
    Map接口
  • 原文地址:https://www.cnblogs.com/youcong/p/13654080.html
Copyright © 2020-2023  润新知