关于redis:SpringBoot234整合Redis实现缓存

3次阅读

共计 21041 个字符,预计需要花费 53 分钟才能阅读完成。

文章次要内容

一、SpringCache 介绍

二、SpringCache 注解

三、注解形式实现 Redis 缓存(Windows 版 Redis)

四、RedisUtils 工具类原生形式实现 Redis 缓存(Windows 版 Redis)

一、SpringCache 介绍

官网文档地址:https://docs.spring.io/spring…

在 Spring Boot 中,数据的缓存治理存储依赖于 Spring 框架中 cache 相干的 org.springframework.cache.Cache 和 org.springframework.cache.CacheManager 缓存管理器接口。

如果程序中没有定义类型为 CacheManager 的 Bean 组件或者是名为 cacheResolver 的 CacheResolver 缓存解析器,Spring Boot 将尝试抉择并启用以下缓存组件(依照指定的程序):

(1)Generic

(2)JCache (JSR-107)(EhCache 3、Hazelcast、Infinispan 等)

(3)EhCache 2.x

(4)Hazelcast

(5)Infinispan

(6)Couchbase

(7)Redis

(8)Caffeine

(9)Simple

下面依照 Spring Boot 缓存组件的加载程序,列举了反对的 9 种缓存组件,在我的项目中增加某个缓存治理组件(例如 Redis)后,Spring Boot 我的项目会抉择并启用对应的缓存管理器。如果我的项目中同时增加了多个缓存组件,且没有指定缓存管理器或者缓存解析器(CacheManager 或者 cacheResolver),那么 Spring Boot 会依照上述程序在增加的多个缓存中优先启用指定的缓存组件进行缓存治理。

Spring Boot 默认缓存治理中,没有增加任何缓存治理组件能实现缓存治理。这是因为开启缓存治理后,Spring Boot 会依照上述列表程序查找无效的缓存组件进行缓存治理,如果没有任何缓存组件,会默认应用最初一个 Simple 缓存组件进行治理 。Simple 缓存组件是 Spring Boot 默认的缓存治理组件, 它默认应用内存中的 ConcurrentMap 进行缓存存储 ,所以在没有增加任何第三方缓存组件的状况下,能够实现内存中的缓存治理,然而咱们 不举荐应用这种缓存治理形式

当在 Spring Boot 默认缓存治理的根底上 引入 Redis 缓存组件 ,即在 pom.xml 文件中增加 Spring Data Redis 依赖启动器后,SpringBoot 会应用RedisCacheConfigratioin 当做失效的主动配置类进行缓存相干的主动拆卸,容器中应用的缓存管理器是RedisCacheManager, 这个缓存管理器创立的 Cache 为 RedisCache, 进而操控 redis 进行数据的缓存

<dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

核心思想:当咱们调用一个办法时会把该办法的参数和返回后果最为一个键值对寄存在缓存中,等下次利用同样的参数来调用该办法时将不会再执行,而是间接从缓存中获取后果进行返回。

了解:springboot 的缓存机制是通过切面编程 aop 来实现的

二、SpringCache 注解

Spring Cache 提供了 @Cacheable、@CachePut、@CacheEvict、@Caching 等注解,在办法上应用。

基于注解形式 SpringCache 引入 Redis 做缓存,须要先理解 @EnableCaching、@CacheConfig、@Cacheable、@CachePut、@CacheEvict、@Caching 相干注解的应用

1、@EnableCaching

开启缓存性能,个别放在启动类上或者自定义的 RedisConfig 配置类上。

2、@CacheConfig

当咱们须要缓存的中央越来越多,能够应用 @CacheConfig(cacheNames = “cacheName”)注解在 class 之上来对立指定 value 的值,对立治理 keys,这时可省略 value,如果你在你的办法仍旧写上了 value,那么仍然以办法的 value 值为准。

示例:

@Service
@CacheConfig(cacheNames = "categories")
public class CategoryServiceImpl implements CategoryService{......}

3、@Cacheable

依据办法对其返回后果进行缓存,下次申请时,如果缓存存在,则间接读取缓存数据返回;如果缓存不存在,则执行办法,并把返回的后果存入缓存中。个别用在查询方法上。查看源码,属性值如下:

属性 / 办法名 解释
value 缓存名,指定了缓存寄存在哪块命名空间(必须)
cacheNames 与 value 差不多,二选一即可
key 缓存的 key,能够应用 SPEL 标签自定义缓存的 key
keyGenerator key 的生存器。key/keyGenerator 二选一应用
cacheManager 指定缓存管理器
cacheResolver 指定获取解析器
condition 条件合乎则缓存
unless 条件合乎则不缓存
sync 是否应用异步模式,默认为 false

4、@CachePut

应用该注解标记的办法,每次都会执行,并将后果存入指定的缓存中。其余办法能够间接从响应的缓存中读取缓存数据,而不须要再去查询数据库。个别用在新增办法上。查看源码,属性值同上 @Cacheable 差不多

5、@CacheEvict

应用该注解标记的办法,会清空指定的缓存。个别用在更新或者删除办法上

查看源码,属性值与 @Cacheable 差不多,独有的两个属性如下:

属性 / 办法名 解释
allEntries 是否清空所有缓存,默认为 false。如果指定为 true,则 办法调用后 将立刻清空所有的缓存
beforeInvocation 是否在办法执行前就清空所有缓存,默认为 false。如果指定为 true,则 办法执行前 就会清空所有的缓存

6、@Caching

该注解能够实现同一个办法上同时应用多种注解。可从其源码看出:

public @interface Caching {Cacheable[] cacheable() default {};
    CachePut[] put() default {};
    CacheEvict[] evict() default {};}

三、注解形式实现 Redis 缓存(Windows 版 Redis)

1、数据库及数据环境筹备

CREATE DATABASE `redistest`CHARACTER SET utf8 COLLATE utf8_general_ci; 
USE `redistest`; 

CREATE TABLE `user`(id INT(11)NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(255)DEFAULT NULL,
  `password` VARCHAR(255)DEFAULT NULL,
  PRIMARY KEY(id)
)ENGINE=INNODB DEFAULT CHARSET=utf8;

INSERT INTO `user` VALUES(1,'张三',"123456789");
INSERT INTO `user` VALUES(2,'李四',"asdfghj");
INSERT INTO `user` VALUES(3,'王麻子',"kjfdskjf");
INSERT INTO `user` VALUES(4,'小明',"hellorworld");
INSERT INTO `user` VALUES(5,'李华',"redis");

2、构建一个 SpringBoot 我的项目,勾选相应的模块,增加 Pom 依赖

增加其余的 Pom 依赖

<!-- mybatis 长久层 -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.1</version>
</dependency>

3、application.properties 配置文件

# ============ 数据库 ============
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/redistest?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=admin

# ============mybatis============
mybatis.mapper-locations=classpath:/mapper/*.xml
mybatis.type-aliases-package=com.cqy.pojo
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

# ============redis============
# 默认是应用 0 号数据库,这里咱们应用 1 号,笔者当初 0 号有其余数据 - -
spring.redis.database=1 
spring.redis.host=localhost
spring.redis.port=6379
# 默认明码为空
spring.redis.password=
# 连接池最大连接数
spring.redis.lettuce.pool.max-active=8
# 连接池最大阻塞等待时间
spring.redis.lettuce.pool.max-wait=-1ms
# 连接池中的最大闲暇连贯
spring.redis.lettuce.pool.max-idle=8
# 连接池中的最小闲暇连贯
spring.redis.lettuce.pool.min-idle=0

4、pojo 实体类

@AllArgsConstructor
@NoArgsConstructor
@Data
public class User {
    
    private int id;
    private String name;
    private String password;
}

5、dao 层的 Mapper 接口

@Repository
@Mapper
public interface UserMapper {

    /**
     * 减少
     * @param user
     * @return
     */
    public int addUser(User user);

    /**
     * 删除
     * @param id
     * @return
     */
    public int deleteUser(@Param("id") int id);

    /**
     * 批改
     * @param user
     * @return
     */
    public int updateUser(User user);

    /**
     * 查问获取所有 User 对象
     * @return
     */
    public List<User> selectUser();

    /**
     * 依据 id 查问获取某个 User 对象
     * @param id
     * @return
     */
    public User selectUserById(@Param("id") int id);
    
    /**
     * 查问一共有几条数据
     * @return
     */
    public int countUser();}

6、Mapper 接口对应的 Mapper.xml 文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cqy.dao.UserMapper">

    <insert id="addUser" parameterType="user">
        insert into `user` (`name`,password) values (#{name},#{password})
    </insert>

    <delete id="deleteUser" parameterType="_int">
        delete from `user` where id =#{id}
    </delete>

    <update id="updateUser" parameterType="user">
        update `user` set `name`=#{name},password=#{password} where id=#{id}
    </update>

    <select id="selectUser" resultType="user">
        select * from `user`
    </select>

    <select id="selectUserById" parameterType="_int" resultType="user">
        select * from `user` where id =#{id}
    </select>
    
    <select id="countUser" resultType="_int">
        select count(*) from `user`
    </select>

</mapper>

7、UserService 和 UserServiceImpl

UserService 接口同 UserMapper 的内容一样,略。

UserServiceImpl:

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    UserMapper userMapper;

    @Override
    public int addUser(User user) {return userMapper.addUser(user);
    }

    @Override
    public int deleteUser(int id) {return userMapper.deleteUser(id);
    }

    @Override
    public int updateUser(User user) {return userMapper.updateUser(user);
    }

    @Override
    public List<User> selectUser() {return userMapper.selectUser();
    }

    @Override
    public User selectUserById(int id) {return userMapper.selectUserById(id);
    }
    
    @Override
    public int countUser() {return userMapper.countUser();
    }
}

8、单元测试简略的 CRUD 是否胜利

@SpringBootTest
class RedisTestSpringbootApplicationTests {

    @Autowired
    UserService userService;

    @Test
    void test() {List<User> users = userService.selectUser();
        for (User user : users) {System.out.println(user);
        }
    }
}

发现报错:

解决:增加 Pom 依赖

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.8.0</version>
</dependency>

9、构建 RedisConfig 配置类

通常咱们都应用 Json 序列化后存入 Redis,而 SpringBoot1.x 和 SpringBoot2.x 版本在自定义 CacheManager 有很大的区别,须要自行研读源码。

在此简略阐明,但不做源码详细分析。

在 SpringBoot1.x 中,RedisCacheManager是能够应用 RedisTemplate 作为参数注入的

  @Bean
    public CacheManager cacheManager(RedisTemplate redisTemplate) {RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
        return cacheManager;
    } 

但在 SpringBoot2.x 中,有很大的不同,RedisCacheManager结构器如下,曾经无奈再应用 RedisTemplate 进行结构

官网文档中:

阐明当初配置 RedisCacheManager 须要一个 RedisCacheConfiguration 来作为配置对象,通过 RedisCacheConfiguration 这个对象来指定对应的序列化策略

SpringBoot2.x 后自定义 CacheManager 有多种形式,笔者此处间接给出本人所用的一种。其余的构建办法,可自行百度,有很多办法。

@Configuration
@SuppressWarnings("all")
@EnableCaching
public class RedisConfig {

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        // 解决查问缓存转换异样的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        // 配置序列化(解决乱码的问题)RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofDays(1))
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                .disableCachingNullValues();

        RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .build();
        return cacheManager;
    }
}

RedisConfig 的 json 序列化配置文章参考:

1、https://blog.csdn.net/weixin_…

2、https://blog.csdn.net/qq_4153…

10、在 UserServiceImpl 应用注解进行 Redis 缓存

留神:须要先在 RedisConfig 加上 @EnableCaching,示意开启缓存性能

@Service
@CacheConfig(cacheNames = "user")
public class UserServiceImpl implements UserService {

    @Autowired
    UserMapper userMapper;

    @Override
    @CachePut(key = "'user-id-'+ #user.id")
    public int addUser(User user) {System.out.println("写入缓存");
        return userMapper.addUser(user);
    }

    @Override
    @CacheEvict(key = "'user-id-'+#p0")// 依据 key 革除缓存,个别该注解标注在批改和删除办法上
    public int deleteUser(int id) {return userMapper.deleteUser(id);
    }

    @Override
    @CacheEvict(key = "'user-id-'+#user.id")// 依据 key 革除缓存,个别该注解标注在批改和删除办法上
    public int updateUser(User user) {System.out.println("更新数据并革除之前的缓存");
        return userMapper.updateUser(user);
    }

    @Override
    @Cacheable(cacheNames = "userList") // 标记读取缓存操作,如果缓存不存在,则调用指标办法,并将后果放入缓存
    public List<User> selectUser() {System.out.println("缓存不存在,执行办法");
        return userMapper.selectUser();}

    @Override
    @Cacheable(key = "'user-id-'+#p0")
    public User selectUserById(int id) {System.out.println("缓存不存在,执行办法");
        return userMapper.selectUserById(id);
    }
}

其中 #p0 是指的第一个参数,#p1 是第二个参数,以此类推。

11、单元测试查看缓存

启动 redis-server 和 RedisDesktopManager

运行单元测试,管理工具查看缓存

@SpringBootTest
class RedisTestSpringbootApplicationTests {

    @Autowired
    UserService userService;

    @Test
    void select() {List<User> users = userService.selectUser();
        for (User user : users) {System.out.println(user);
        }
    }

    @Test
    void selectById() {User users = userService.selectUserById(3);
        System.out.println(users);
    }

    @Test
    void add() {userService.addUser(new User(6,"小红","56458848"));
    }

    @Test
    void update() {userService.updateUser(new User(6,"纸飞机","1111111"));
    }

    @Test
    void delete() {userService.deleteUser(6);
    }
}

四、RedisUtils 工具类原生形式实现 Redis 缓存(Windows 版 Redis)

应用 SpringCache 的注解形式实现 Redis 缓存,底层逻辑原理其实就是 Redis 的 set、get 命令操作 key-value,将操作返回的后果存到 Redis 中,下次执行同样操作的时候,进行判断逻辑看 Redis 中是否有值,存在的话就间接从 Redis 中拿 value,实现缓存成果。

因而,咱们可间接利用 RedisUtils 的形式,进行逻辑的 set、get 实现缓存。这种形式很多时候序列化和 key 的设置都绝对更灵便一些,但绝对也较简单一些。

1、数据库及数据环境筹备

2、构建一个 SpringBoot 我的项目,勾选相应的模块,增加 Pom 依赖

3、application.properties 配置文件

4、pojo 实体类

5、dao 层的 Mapper 接口

6、Mapper 接口对应的 Mapper.xml 文件

7、UserService 和 UserServiceImpl

8、单元测试简略的 CRUD 是否胜利

以上步骤都同第三局部一样,不再赘述。

9、构建 RedisConfig 配置类

RedisConfig 中自定义 redisTemplate 的 bean

@Configuration
@SuppressWarnings("all")
public class RedisConfig {@Bean(name="myredisTemplate")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        //Json 序列化设置
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        // 通过 ObjectMapper 本义 json
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        //String 类型的序列化
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        //key 采纳 String 的序列化形式
        template.setKeySerializer(stringRedisSerializer);
        //hash 的 key 也采纳 String 的序列化形式
        template.setHashKeySerializer(stringRedisSerializer);
        //value 的序列化形式采纳 jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        //hash 的 value 序列化形式采纳 jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
}

10、RedisUtils 封装工具类筹备


@Component
public class RedisUtils {

    @Autowired
    @Qualifier("myredisTemplate")
    private RedisTemplate<String,Object> redisTemplate;

    // =============================common============================
    /**
     * 指定缓存生效工夫
     * @param key 键
     * @param time 工夫(秒)* @return
     */
    public boolean expire(String key,long time){
        try {if (time > 0){redisTemplate.expire(key,time, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception e){e.printStackTrace();
            return false;
        }
    }


    /**
     * 依据 key 获取过期工夫
     * @param key 键  不能为 null
     * @return 工夫(秒)返回 0 代表为永恒无效
     */
    public long getExpire(String key){return redisTemplate.getExpire(key,TimeUnit.SECONDS);
    }




    /**
     * 判断 key 是否存在
     * @param key  键
     * @return  true 的话存在,false 不存在
     */
    public boolean hasKey(String key){
        try {return redisTemplate.hasKey(key);
        } catch (Exception e){e.printStackTrace();
            return false;
        }
    }


    /**
     * 删除缓存
     * @param key  能够传一个 key 或多个 key
     */
    @SuppressWarnings("unchecked")
    public void del(String... key){if (key!=null && key.length>0){if (key.length==1){redisTemplate.delete(key[0]);
            } else {redisTemplate.delete(CollectionUtils.arrayToList(key));
            }
        }
    }


    // ============================String=============================


    /**
     * 一般缓存获取
     * @param key 键
     * @return 值
     */
    public Object get(String key) {return key == null ? null : redisTemplate.opsForValue().get(key);
    }


    /**
     * 一般缓存放入
     * @param key   键
     * @param value 值
     * @return true 胜利 false 失败
     */
    public boolean set(String key, Object value) {
        try {redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {e.printStackTrace();
            return false;
        }
    }


    /**
     * 一般缓存放入并设置工夫
     * @param key   键
     * @param value 值
     * @param time  工夫(秒) time 要大于 0 如果 time 小于等于 0 将设置无限期
     * @return true 胜利 false 失败
     */
    public boolean set(String key, Object value, long time) {
        try {if (time > 0) {redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            } else {set(key, value);
            }
            return true;
        } catch (Exception e) {e.printStackTrace();
            return false;
        }
    }


    /**
     * 递增
     * @param key   键
     * @param delta 要减少几(大于 0)
     */
    public long incr(String key, long delta) {if (delta < 0) {throw new RuntimeException("递增因子必须大于 0");
        }
        return redisTemplate.opsForValue().increment(key, delta);
    }


    /**
     * 递加
     * @param key   键
     * @param delta 要缩小几(小于 0)
     */
    public long decr(String key, long delta) {if (delta < 0) {throw new RuntimeException("递加因子必须大于 0");
        }
        return redisTemplate.opsForValue().increment(key, -delta);
    }


    // ================================HashMap=================================


    /**
     * HashGet
     * @param key  键 不能为 null
     * @param item 项 不能为 null
     */
    public Object hget(String key, String item) {return redisTemplate.opsForHash().get(key, item);
    }


    /**
     * 获取 hashKey 对应的所有键值
     * @param key 键
     * @return 对应的多个键值
     */
    public Map<Object, Object> hmget(String key) {return redisTemplate.opsForHash().entries(key);
    }


    /**
     * HashSet
     * @param key 键
     * @param map 对应多个键值
     */
    public boolean hmset(String key, Map<String, Object> map) {
        try {redisTemplate.opsForHash().putAll(key, map);
            return true;
        } catch (Exception e) {e.printStackTrace();
            return false;
        }
    }


    /**
     * HashSet 并设置工夫
     * @param key  键
     * @param map  对应多个键值
     * @param time 工夫(秒)
     * @return true 胜利 false 失败
     */
    public boolean hmset(String key, Map<String, Object> map, long time) {
        try {redisTemplate.opsForHash().putAll(key, map);
            if (time > 0) {expire(key, time);
            }
            return true;
        } catch (Exception e) {e.printStackTrace();
            return false;
        }
    }


    /**
     * 向一张 hash 表中放入数据, 如果不存在将创立
     *
     * @param key   键
     * @param item  项
     * @param value 值
     * @return true 胜利 false 失败
     */
    public boolean hset(String key, String item, Object value) {
        try {redisTemplate.opsForHash().put(key, item, value);
            return true;
        } catch (Exception e) {e.printStackTrace();
            return false;
        }
    }


    /**
     * 向一张 hash 表中放入数据, 如果不存在将创立
     *
     * @param key   键
     * @param item  项
     * @param value 值
     * @param time  工夫(秒) 留神: 如果已存在的 hash 表有工夫, 这里将会替换原有的工夫
     * @return true 胜利 false 失败
     */
    public boolean hset(String key, String item, Object value, long time) {
        try {redisTemplate.opsForHash().put(key, item, value);
            if (time > 0) {expire(key, time);
            }
            return true;
        } catch (Exception e) {e.printStackTrace();
            return false;
        }
    }


    /**
     * 删除 hash 表中的值
     *
     * @param key  键 不能为 null
     * @param item 项 能够使多个 不能为 null
     */
    public void hdel(String key, Object... item) {redisTemplate.opsForHash().delete(key, item);
    }


    /**
     * 判断 hash 表中是否有该项的值
     *
     * @param key  键 不能为 null
     * @param item 项 不能为 null
     * @return true 存在 false 不存在
     */
    public boolean hHasKey(String key, String item) {return redisTemplate.opsForHash().hasKey(key, item);
    }


    /**
     * hash 递增 如果不存在, 就会创立一个 并把新增后的值返回
     *
     * @param key  键
     * @param item 项
     * @param by   要减少几(大于 0)
     */
    public double hincr(String key, String item, double by) {return redisTemplate.opsForHash().increment(key, item, by);
    }


    /**
     * hash 递加
     *
     * @param key  键
     * @param item 项
     * @param by   要缩小记(小于 0)
     */
    public double hdecr(String key, String item, double by) {return redisTemplate.opsForHash().increment(key, item, -by);
    }


    // ============================set=============================


    /**
     * 依据 key 获取 Set 中的所有值
     * @param key 键
     */
    public Set<Object> sGet(String key) {
        try {return redisTemplate.opsForSet().members(key);
        } catch (Exception e) {e.printStackTrace();
            return null;
        }
    }


    /**
     * 依据 value 从一个 set 中查问, 是否存在
     *
     * @param key   键
     * @param value 值
     * @return true 存在 false 不存在
     */
    public boolean sHasKey(String key, Object value) {
        try {return redisTemplate.opsForSet().isMember(key, value);
        } catch (Exception e) {e.printStackTrace();
            return false;
        }
    }


    /**
     * 将数据放入 set 缓存
     *
     * @param key    键
     * @param values 值 能够是多个
     * @return 胜利个数
     */
    public long sSet(String key, Object... values) {
        try {return redisTemplate.opsForSet().add(key, values);
        } catch (Exception e) {e.printStackTrace();
            return 0;
        }
    }


    /**
     * 将 set 数据放入缓存
     *
     * @param key    键
     * @param time   工夫(秒)
     * @param values 值 能够是多个
     * @return 胜利个数
     */
    public long sSetAndTime(String key, long time, Object... values) {
        try {Long count = redisTemplate.opsForSet().add(key, values);
            if (time > 0)
                expire(key, time);
            return count;
        } catch (Exception e) {e.printStackTrace();
            return 0;
        }
    }


    /**
     * 获取 set 缓存的长度
     *
     * @param key 键
     */
    public long sGetSetSize(String key) {
        try {return redisTemplate.opsForSet().size(key);
        } catch (Exception e) {e.printStackTrace();
            return 0;
        }
    }


    /**
     * 移除值为 value 的
     *
     * @param key    键
     * @param values 值 能够是多个
     * @return 移除的个数
     */


    public long setRemove(String key, Object... values) {
        try {Long count = redisTemplate.opsForSet().remove(key, values);
            return count;
        } catch (Exception e) {e.printStackTrace();
            return 0;
        }
    }

    // ===============================list=================================


    /**
     * 获取 list 缓存的内容
     *
     * @param key   键
     * @param start 开始
     * @param end   完结 0 到 - 1 代表所有值
     */
    public List<Object> lGet(String key, long start, long end) {
        try {return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {e.printStackTrace();
            return null;
        }
    }


    /**
     * 获取 list 缓存的长度
     *
     * @param key 键
     */
    public long lGetListSize(String key) {
        try {return redisTemplate.opsForList().size(key);
        } catch (Exception e) {e.printStackTrace();
            return 0;
        }
    }


    /**
     * 通过索引 获取 list 中的值
     *
     * @param key   键
     * @param index 索引 index>= 0 时,0 表头,1 第二个元素,顺次类推;index<0 时,-1,表尾,- 2 倒数第二个元素,顺次类推
     */
    public Object lGetIndex(String key, long index) {
        try {return redisTemplate.opsForList().index(key, index);
        } catch (Exception e) {e.printStackTrace();
            return null;
        }
    }


    /**
     * 将 list 放入缓存
     *
     * @param key   键
     * @param value 值
     */
    public boolean lSet(String key, Object value) {
        try {redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {e.printStackTrace();
            return false;
        }
    }


    /**
     * 将 list 放入缓存
     * @param key   键
     * @param value 值
     * @param time  工夫(秒)
     */
    public boolean lSet(String key, Object value, long time) {
        try {redisTemplate.opsForList().rightPush(key, value);
            if (time > 0)
                expire(key, time);
            return true;
        } catch (Exception e) {e.printStackTrace();
            return false;
        }
    }


    /**
     * 将 list 放入缓存
     *
     * @param key   键
     * @param value 值
     * @return
     */
    public boolean lSet(String key, List<Object> value) {
        try {redisTemplate.opsForList().rightPushAll(key, value);
            return true;
        } catch (Exception e) {e.printStackTrace();
            return false;
        }
    }

    /**
     * 将 list 放入缓存
     *
     * @param key   键
     * @param value 值
     * @param time  工夫(秒)
     * @return
     */
    public boolean lSet(String key, List<Object> value, long time) {
        try {redisTemplate.opsForList().rightPushAll(key, value);
            if (time > 0)
                expire(key, time);
            return true;
        } catch (Exception e) {e.printStackTrace();
            return false;
        }
    }

    /**
     * 依据索引批改 list 中的某条数据
     *
     * @param key   键
     * @param index 索引
     * @param value 值
     * @return
     */

    public boolean lUpdateIndex(String key, long index, Object value) {
        try {redisTemplate.opsForList().set(key, index, value);
            return true;
        } catch (Exception e) {e.printStackTrace();
            return false;
        }
    }

    /**
     * 移除 N 个值为 value
     *
     * @param key   键
     * @param count 移除多少个
     * @param value 值
     * @return 移除的个数
     */

    public long lRemove(String key, long count, Object value) {
        try {Long remove = redisTemplate.opsForList().remove(key, count, value);
            return remove;
        } catch (Exception e) {e.printStackTrace();
            return 0;
        }
    }
}

11、在 UserServiceImpl 中进行 redis 缓存逻辑 bianxie


@Service
public class UserServiceImpl implements UserService {

    @Autowired
    UserMapper userMapper;
    @Autowired
    RedisUtils redisUtils;

    public static final String CACHE_KEY_USER="user:";

    @Override
    public int addUser(User user) {
        // 先间接批改数据库中的数据,办法执行后再更新缓存
        int i = userMapper.addUser(user);
        redisUtils.set(CACHE_KEY_USER+user.getId(),user);
        return i;
    }

    @Override
    public int deleteUser(int id) {
        // 办法执行后删除 redis 中相应的缓存
        int i = userMapper.deleteUser(id);
        redisUtils.del(CACHE_KEY_USER+id);
        return i;
    }

    @Override
    public int updateUser(User user) {
        // 先间接批改数据库中的数据
        int i = userMapper.updateUser(user);
        // 办法执行后更新 redis 中相应的缓存
        int id = user.getId();
        redisUtils.set(CACHE_KEY_USER+user.getId(),user);
        return i;
    }

    @Override
    public List<User> selectUser() {int i = countUser();
        Object object = redisUtils.get(CACHE_KEY_USER + "number:"+i);
        // 判断 redis 中是否存在缓存的 key-value
        if (null != object){
            // 有,间接返回
            return (List<User>) object;
        }
        // 没有,去数据库中查问,并将查问的后果存到 redis 中
        List<User> users = userMapper.selectUser();
        redisUtils.set(CACHE_KEY_USER + "number:"+i,users);
        return users;
    }

    @Override
    public User selectUserById(int id) {Object object = redisUtils.get(CACHE_KEY_USER + id);
        // 判断 redis 中是否存在缓存的 key-value
        if (null != object){
            // 有,间接返回
            return (User) object;
        }
        // 没有,去数据库中查问,并将查问的后果存到 redis 中
        User user = userMapper.selectUserById(id);
        redisUtils.set(CACHE_KEY_USER + id,user);
        return user;
    }

    @Override
    public int countUser() {return userMapper.countUser();
    }
}

12、单元测试查看缓存

@SpringBootTest
class RedisTest01SpringbootApplicationTests {

    @Autowired
    UserService userService;

    @Test
    void selectById() {User user = userService.selectUserById(3);
        System.out.println(user);
    }

    @Test
    void select() {List<User> users = userService.selectUser();
        for (User user : users) {System.out.println(user);
        }
    }

    @Test
    void add() {userService.addUser(new User(6,"纸飞机","1998dsadsasd"));
    }

    @Test
    void delete() {userService.deleteUser(6);
    }

    @Test
    void update() {userService.updateUser(new User(6,"纸飞机 666","helloredis"));
    }
}

以上只是特地简略的 redis 操作,其余的设置 key 的过期工夫等,间接应用 redisUtils 进行设置即可。

五、总结

redis 缓存实质仍旧是操作 redis 其中的五大数据类型,须要熟练掌握,并且能通晓用在何处,怎么用。

参考:

1、https://segmentfault.com/a/11… 整合 Redis 缓存实现 指标字节的秃秃
2、https://juejin.im/post/684490… Spring Boot 2.X(七):Spring Cache 应用 朝雾轻寒
3、https://juejin.im/post/684490… 优雅的缓存解决方案 –SpringCache 和 Redis 集成(SpringBoot) 米奇罗


谢谢您看完这篇技术文章

如果能对您有所帮忙

那将是一件很美妙的事件

放弃好奇心的一生学习也是极棒的事

愿世界简略又多彩

转载请注明出处

​ ——纸飞机

正文完
 0