---随笔--Redis的学习以及在Spring Boot中的整合使用(RedisTemplate、Redisson分布式锁)

引言

在现代Web应用开发中,性能和可扩展性至关重要。Redis作为一个高性能的内存数据结构存储系统,因其卓越的速度和丰富的功能而广受欢迎。而将Redis集成到Spring Boot项目中,可以显著提升应用程序的响应速度和处理能力。

本文将简要介绍Redis的用法及如何在Spring Boot中配置和使用Redis,涵盖基础配置和常见操作。通过阅读本文,您将掌握Redis的使用及如何在Spring Boot项目中高效使用Redis,优化应用性能,提升用户体验。 (若想直接跳到代码部分可以直接点目录哈~)

关于Redis的安装可以在网上查阅相关资料,这里就不费时间写如何安装了,还是蛮简单的,可以参考下‘明金同学’的这篇文章:Window下Redis的安装和部署详细图文教程,或者参考‘阿里社区’的这篇文章:Redis安装与配置指南:适用于Windows、Mac和Linux系统的详细教程,也可以参考’JAVA白大仙’的这篇文章:Windows版Docker安装Redis教程(保姆级),适合开发环境快速提供Redis服务

1. 什么是Redis

Redis(Remote Dictionary Server)是一个开源(BSD许可)的内存数据结构存储系统。它可以用作数据库、缓存和消息代理。Redis支持多种数据结构,例如字符串(String)、哈希表(Hash)、列表(List)、集合(Set)、有序集合(Sorted Set)高级数据类型包括位图 (Bitmaps)、概率性数据结构 (HyperLogLog)、地理空间 (Geospatial)。它的主要特点和功能包括:

  1. 高性能:Redis通过将数据存储在内存中,实现了非常高的读写速度,读写操作可以在毫秒级别内完成。
  2. 持久化:尽管Redis的数据主要存储在内存中,但它支持将数据异步地保存到磁盘,以实现持久化。支持RDB(快照)和AOF(Append Only File)两种持久化方式。
  3. 丰富的数据类型:Redis不仅支持简单的键值对,还支持复杂的数据结构,如列表、集合、有序集合和哈希表,这使得它在处理复杂数据时更加灵活。
  4. 原子操作:Redis提供了一组丰富的原子操作,这些操作保证了数据的一致性和完整性。
  5. 发布/订阅:Redis支持发布/订阅消息模式,可以用于构建实时消息系统。
  6. 主从复制:Redis支持主从复制,允许数据在多个Redis实例之间进行同步,从而提高数据的可用性和可靠性。
    高可用性和分片:通过Redis Sentinel和Redis Cluster,可以实现高可用性和自动分片,从而支持更大规模的集群和更高的故障容忍度。
    Redis广泛应用于缓存、会话存储、实时分析、消息队列和排行榜等场景,是提升Web应用性能和可扩展性的强大工具。

2. Redis的数据结构

Redis是一种高效的内存数据结构存储系统,支持多种数据结构和丰富的操作。以下是Redis的几种主要数据结构及其常见用法:

  1. 字符串 (String)
    字符串是Redis中最基本的数据结构,每个键对应一个字符串值。
  • 用法示例【SET、GET、INCR、MGET 、MSET 】:
SET key "value"           # 设置字符串值
GET key                   # 获取字符串值value
INCR key                  # 将字符串值自增1(要求值是整数)
MGET key1 key2			  # 同时获取一个或多个 key 的值
MSET key1 key2			  # 同时设置一个或多个 key-value 对
  1. 哈希 (Hash)
    哈希是一种键值对集合,适用于存储对象。例如,用户信息。
  • 用法示例【HSET、HGET、HGETALL、HEXISTS、HKEYS、HVALS 】:
HSET user:1 name "Alice"  # 设置哈希字段
HGET user:1 name          # 获取哈希字段
HGETALL user:1            # 获取所有哈希字段和值
HEXISTS user:1 name		  # 检查指定字段是否存在于 Hash 中
HKEYS user:1			  # 获取 Hash 中所有字段的列表
HVALS user:1			  # 获取 Hash 中所有值的列表
  1. 列表 (List)
    列表是一个有序的字符串集合,可以添加元素到列表的两端(左端和右端)。
  • 用法示例【LPUSH、RPUSH、LPOP、RPOP、LRANGE、LINDEX 、LSET 、LTRIM 】:
LPUSH tasks "task1"       # 从左端插入元素
RPUSH tasks "task2"       # 从右端插入元素
LPOP tasks                # 从左端弹出元素
RPOP tasks                # 从右端弹出元素
LRANGE tasks 0 -1         # 获取列表中所有元素
LINDEX tasks index 	  # 通过索引获取列表中的元素
LSET tasks index value	  # 将列表中指定索引的元素设置为另一个值
LTRIM tasks start stop   # 修剪(缩减)一个列表,使其只包含指定范围的元素
  1. 集合 (Set)
    集合是一个无序的字符串集合,适用于存储不重复的数据。
  • 用法示例【SADD、SMEMBERS、SISMEMBER、SREM、SUNION、SINTER 、SDIFF 、SCARD、SRANDMEMBER、SPOP 】:
SADD myset "value1"       # 添加元素到集合
SADD myset "value2"
SMEMBERS myset            # 获取集合中的所有元素
SISMEMBER myset "value1"  # 判断指定元素是否存在于集合中
SREM myset "value1"       # 从集合中移除元素
SUNION set1 set2		  # 返回两个或多个集合的并集
SINTER set1 set2		  # 返回两个或多个集合的交集
SDIFF set1 set2			  # 返回两个或多个集合的差集
SCARD myset				  # 获取集合中元素的数量
SRANDMEMBER myset 2  	  # 返回两个随机元素
SPOP myset 1  			  # 随机移除并返回一个元素
  1. 有序集合 (Sorted Set)
    有序集合与集合类似,但每个元素都会关联一个评分(score),可以根据评分排序。
  • 用法示例【ZADD、ZRANGE(ZREVRANGE)、ZRANGEBYSCORE(ZREVRANGEBYSCORE)、ZREM、ZINCRBY 、ZSCORE 】:
ZADD myzset 1 "value1"    # 添加元素及其评分
ZADD myzset 2 "value2"
ZRANGE myzset 0 -1 WITHSCORES  # 获取所有元素及其评分,按分数升序排列
ZRANGEBYSCORE myzset min max WITHSCORES  # 获取分数在 min 和 max 之间的元素及其分数
ZREM myzset "value1"      # 移除元素
ZINCRBY myzset 2 "value2"  # 将元素 "value2" 的分数增加 2
ZSCORE myzset "value2"
  1. 位图 (Bitmaps)
    位图是一个字符串,在位级别上操作。可以将其视为一个大位数组。
  • 用法示例【SETBIT、GETBIT、BITCOUNT】:
SETBIT bitmap 10 1        # 将第10位置为1
GETBIT bitmap 10          # 获取第10位的值
BITCOUNT bitmap           # 统计位图中值为1的位数
  1. HyperLogLog
    HyperLogLog是一种概率性数据结构,用于基数统计(即不重复元素的近似计数)。
  • 用法示例【PFADD、PFCOUNT】:
PFADD hll "elem1" "elem2" # 添加元素到HyperLogLog
PFCOUNT hll               # 获取不重复元素的近似计数
  1. 地理空间 (Geospatial)
    Redis支持地理空间索引,允许存储地理位置及执行地理空间半径查询。
  • 用法示例【GEOADD、GEORADIUS】:
GEOADD locations 13.361389 38.115556 "Palermo"  # 添加地理位置
GEORADIUS locations 15 37 200 km                # 查询半径内的位置

3. Redis其它常用命令

除了上述数据结构常用的命令外,Redis还提供了许多特殊的操作命令:

  1. TTL
    TTL命令用于获取指定键的剩余生存时间(Time To Live),即距离过期还有多少秒。
  • 用法示例:
SET key "value"     # 设置键 key 的值为 value
EXPIRE key 60       # 设置键 key 的过期时间为 60 秒
TTL key             # 获取键 key 的剩余生存时间
  1. EXPIRE
    EXPIRE命令用于设置指定键的过期时间,单位为秒。当键过期后,将自动被删除
  • 用法示例:
SET session "token"   # 设置会话 session 的值为 token
EXPIRE session 3600   # 设置 session 的过期时间为 3600 秒(1小时)
  1. DEL
    DEL命令用于删除指定键及其对应的值
  • 用法示例:
SET key "value"     # 设置键 key 的值为 value
DEL key             # 删除键 key
  1. KEYS
    KEYS命令用于获取所有符合给定模式的键。
  • 用法示例:
KEYS *              # 获取所有键
KEYS user:*         # 获取以 user: 开头的键
  1. SETNX
    SETNX命令用于设置键的值,但仅在键不存在时才执行设置操作。如果键已经存在,则该命令不会执行任何操作。
  • 用法示例:
SETNX key "value"   # 当键 key 不存在时,设置其值为 value

这个命令通常用于设置分布式锁,确保同一时刻只有一个客户端能够获取锁。

  1. SETEX
    SETEX命令用于设置键的值,并同时设置该键的过期时间(单位为秒,原子操作)。
  • 用法示例:
SETEX key 60 "value"   # 设置键 key 的值为 value,并同时设置过期时间为60秒
  1. PUBLISH 、SUBSCRIBE、UNSUBSCRIBE
    使用 SUBSCRIBE 命令让客户端订阅一个或多个频道。当客户端订阅了频道后,它可以接收到所有发送到这些频道的消息。
SUBSCRIBE channel1

使用 PUBLISH 命令来发布消息到一个指定的频道。任何订阅了该频道的客户端都将收到这条消息

PUBLISH channel1 "Hello, World!"

订阅频道的客户端会实时接收到所有发布到这些频道的消息。消息的接收是自动的,一旦客户端订阅了频道,就会保持监听状态直到取消订阅

如果客户端不再希望接收某个频道的消息,可以使用 UNSUBSCRIBE 命令来取消订阅

UNSUBSCRIBE channel1
  1. FLUSHDB
    FLUSHDB命令用于清空当前数据库中的所有键,不影响其它数据库。
  • 用法示例:
FLUSHDB   # 清空当前数据库
  1. FLUSHALL
    FLUSHALL命令用于清空所有数据库的所有键。
  • 用法示例:
FLUSHALL  # 清空所有数据库
  1. RENAME
    RENAME命令用于修改键的名字。
  • 用法示例:
SET mykey "value"   # 设置键 mykey 的值
RENAME mykey newkey # 将 mykey 重命名为 newkey
  1. TYPE
    TYPE命令用于获取键的数据类型。
  • 用法示例:
TYPE mykey  # 获取 mykey 的数据类型
  1. DBSIZE
    DBSIZE命令用于获取当前数据库的键的数量。
  • 用法示例:
DBSIZE  # 获取当前数据库的键的数量
  1. PERSIST
    PERSIST命令用于移除键的过期时间,使其变为持久键
  • 用法示例:
SET mykey "value" EX 60   # 设置 mykey 的过期时间为60秒
PERSIST mykey             # 移除 mykey 的过期时间
  1. INFO
    INFO命令用于获取服务器的信息和统计数据。
  • 用法示例:
INFO   # 获取服务器的详细信息
INFO memory  # 获取关于内存的统计信息
  1. MULTI、EXEC、DISCARD、WATCH
    MULTI :通过该命令来开启一个事务,后续的操作命令统统填进该事务队列中,直到执行或取消
    EXEC:该命令来执行所有队列中的命令
    DISCARD: 在执行 EXEC 之前决定不再继续事务,可以使用命令来取消事务
    WATCH:在开启事务之前,可以使用 WATCH 命令来监控一个或多个键。如果在执行事务之前这些键的值被修改,那么事务将不会执行,EXEC 命令将返回 nil。
WATCH balance # 监控余额,防止在事务开启前值被更改
GET balance
# 假设余额检查后足够进行某项操作
MULTI # 开启事务
DECRBY balance 100  #命令入队
LPUSH changelog "100 deducted from balance"  #命令入队
#DISCARD 		# 取消上边事务队列中的事务
EXEC  			#将队列中的命令依次执行,保证事务

4. 小插曲之Redis面试常考

Redis也是后端开发技术面试的常考的一个知识,我们也是需要多了解了解的,有些理论知识也是挺有帮助的,有时可以很快地解决未知的bug。下面一起来看看Redis常考的面试题吧,浅浅过一下,查漏补缺。

  1. 基本概念和数据类型: 了解 Redis 是什么,它的特点和用途,为什么那么快。 掌握各种数据类型的使用和特点,如字符串(String),列表(List),集合(Set),有序集合(Sorted Set),哈希(Hash)。
  2. 命令熟悉度: 需要对常用的 Redis 命令有深入的了解,比如刚刚讨论的字符串和列表操作命令。 如何使用这些命令来实现具体的功能,比如实现队列、堆栈、消息发布/订阅等。
  3. 持久化机制: 理解 Redis 的持久化选项:RDB(快照)和 AOF(追加文件)。 知道它们的工作原理、优缺点以及如何配置。
  4. 事务处理: 如何在 Redis 中使用事务,了解 MULTI, EXEC, WATCH, 和 DISCARD 命令。 事务的特性,如原子性、隔离级别。
  5. 性能优化和监控: 熟悉如何优化 Redis 配置和性能。 了解监控工具和相关的性能指标。
  6. 高可用性与集群: Redis 的主从复制机制,故障转移和数据一致性。 Redis 集群的工作原理,如何设置和运维一个 Redis 集群。
  7. 特殊问题处理: 对缓存穿透、缓存雪崩和缓存击穿的理解和解决方案。
  8. 安全性: 如何安全地配置和使用 Redis,包括网络安全和数据安全。

Redis的面试题涵盖许多,更多的也可以参考下’涝山道士‘的【精选】30+Redis面试题整理(2024)附答案

5. 正篇:Redis在Spring Boot中的使用!(着急的小伙伴可以直接跳这里看噢)

5.1 在maven文件中导入Redis依赖

在pom.xml文件下的dependencies标签中添加以下标签:

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

这里需要注意,添加了一个spring-boot-starter-web的依赖,因为这个依赖里包含了Redis所需的序列化Jackson依赖,所以需要添加进来,如果不添加spring-boot-starter-web依赖,则需要手动再添加jackson-databind的相关依赖

5.2 配置Redis连接信息

spring:
  application:
    name: myRedis
  data:
    redis:
      host: localhost
      port: 6379
      database: 0 # Redis默认提供16个数据库(索引0-15),一般从第0个使用
      password: <PASSWORD> # 如果有,没有则删除
      # 使用lettuce作为连接客户端,若需要使用jedis需要再导入依赖并配置
      lettuce:
        # 连接池配置
        pool:
          max-active: 8 #最大活跃连接数为8
          max-idle: 8   # 最大空闲连接数为8
          min-idle: 0   # 最小空闲连接数为0
          max-wait: -1ms # 最大等待时间为-1ms,即不限制等待时间

5.3 使用RedisTemplate进行操作(记得运行redis server)

5.3.1 编写RedisTemplate配置类
@Configuration
public class RedisConfig {

    /***
     * 这段代码的主要功能是创建和配置一个RedisTemplate bean,
     * 在Redis数据库中设置键、值、哈希键和哈希值的序列化器,以与Redis数据库交互。
     * 该代码配置了RedisTemplate与连接工厂和特定的序列化器,用于处理Redis中的键值对和哈希结构,允许以JSON格式存储和检索Redis数据库中的对象。
     * @param factory 接受一个RedisConnectionFactory类型的参数factory,这个参数是由Spring自动注入的(yaml文件里配置了),用于连接到Redis数据库。
     * @return
     */
    @Bean
    // 在控制台输出信息,表示正在使用自定义配置的 RedisTemplate
    System.out.println("使用自定义的RedisTemplate配置");

    // 创建一个 RedisTemplate<String, Object> 实例
    RedisTemplate<String, Object> template = new RedisTemplate<>();
    // 设置 Redis 连接工厂,这是必须的,以便模板能够访问 Redis 服务器
    template.setConnectionFactory(factory);

    // 创建一个用于序列化字符串的序列化器
    StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
    
    // 设置键(key)(value)的序列化方式。这里使用字符串序列化器,可以确保 key和value 的存储和读取不会出现乱码等问题
    template.setKeySerializer(stringRedisSerializer);
    template.setValueSerializer(stringRedisSerializer);
    template.setHashKeySerializer(stringRedisSerializer);
    template.setHashValueSerializer(stringRedisSerializer);

    // 初始化 RedisTemplate 实例的各项属性,确保它在返回前是完全可用的
    template.afterPropertiesSet();

    // 返回配置好的 RedisTemplate 实例
    return template;
}

一开始我使用’GenericJackson2JsonRedisSerializer’来对值进行序列化,但是后面测试的时候发现,在存储字符串的时候会把双引号""也存储进去,虽然读取的时候读出来的数据没有双引号,但是在客户端上get或者通过可视化查看值时还是不是很好看的,所以都使用‘StringRedisSerializer’ 来序列化了,可能这也会带来一些问题,需要再研究了。

5.3.2 注入使用RedisTemplate
@Component
public class MyRedisUtils{

    private final RedisTemplate<String, Object> redisTemplate;
    
    //构造器注入
    @Autowired
    public MyRedisUtils(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

}

这里我使用了Spring框架推荐的构造器注入方式,主要是这几点原因:

  1. 不变性和线程安全: 通过构造器注入,可以确保依赖对象在创建时就完全初始化。这样,redisTemplate 字段可以被声明为 final,意味着一旦赋值后就不可更改。这种不变性有助于保证线程安全,因为这个对象状态不会再发生变化。

  2. 依赖关系的清晰性: 构造器注入强制性地要求提供所有必需的依赖,否则对象无法被创建。这种方式使得依赖关系更加明显,不会隐藏在类的内部,有助于维护和理解代码。当查看构造函数时,可以清楚地看到类的所有依赖项,这比在类中间或底部查找注入点要直观得多。

  3. 与Spring框架的兼容性: 在现在的Spring主流版本上,如果类只有一个构造函数,Spring会默认使用这个构造函数进行依赖注入,即使没有显式地标注
    @Autowired。这表明Spring团队推荐使用构造器注入,而且这种方式与Spring的自动装配机制非常兼容。

  4. 测试的便利性: 使用构造器注入可以更容易地编写单元测试,因为可以在不启动Spring容器的情况下,通过直接传递构造参数来创建对象的实例。这使得测试更快、更独立,不依赖于Spring的配置或环境。

  5. 代码整洁与组织性: 构造器注入通常可以促使开发者编写更整洁、更有组织的代码。通过构造器集中管理依赖,可以避免在类中散布多个注入点,使类的结构更加清晰和模块化。

5.3.3 Redis工具类完整代码(可自行添加方法)
@Component
public class MyRedisUtils {

    private final RedisTemplate<String, Object> redisTemplate;

    @Autowired
    public MyRedisUtils(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 设置指定key的值
     *
     * @param key   键
     * @param value 值
     */
    public void set(String key, Object value) {
        System.out.println("set key: " + key + " value: " + value);
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 获取指定key的值
     *
     * @param key 键
     * @return 对应的值
     */
    public Object get(String key) {
        Object val = redisTemplate.opsForValue().get(key);
        System.out.println("get key's value: " + val);
        return val;
    }

    /**
     * 删除指定key
     *
     * @param key 键
     */
    public void delete(String key) {
        System.out.println("delete key: " + key);
        redisTemplate.delete(key);
    }

    /**
     * 判断指定key是否存在
     *
     * @param key 键
     * @return 存在则返回true,否则返回false
     */
    public boolean exists(String key) {
        Boolean hasKey = redisTemplate.hasKey(key);
        System.out.println("whether exists key->" + key + ":" + hasKey);
        return Boolean.TRUE.equals(hasKey);
    }

    /**
     * 为指定key设置过期时间
     *
     * @param key     键
     * @param timeout 过期时间(以秒为单位)
     */
    public void expire(String key, long timeout) {
        System.out.println("expire key: " + key + " timeout: " + timeout);
        redisTemplate.expire(key, Duration.ofSeconds(timeout));
    }
}

5.4 测试Redis操作

编写测试类:

@SpringBootTest
class MyRedisApplicationTests {

    @Autowired
    private MyRedisUtils myRedisUtils;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Test
    public void testMyRedisUtilsIsNotNull() {
        assertNotNull(myRedisUtils);
    }

    @Test
    public void testSetAndGet() {
        String key = "testKey";
        String value = "testValue";

        myRedisUtils.set(key, value);
        assertEquals(value, myRedisUtils.get(key));

        // 清理
        myRedisUtils.delete(key);
    }

    @Test
    public void testDelete() {
        String key = "testKey";
        myRedisUtils.set(key, "value");
        assertTrue(myRedisUtils.exists(key));

        myRedisUtils.delete(key);
        assertFalse(myRedisUtils.exists(key));
    }

    @Test
    public void testExpire() throws InterruptedException {
        String key = "testKey";
        myRedisUtils.set(key, "value");
        myRedisUtils.expire(key, 1);  // 设置1秒后过期

        Thread.sleep(1500);  // 等待超过1秒确保键已过期
        assertNull(myRedisUtils.get(key));
    }
}

执行结果:
执行结果

5.5 Redisson分布式锁的使用

除了RedisTemplate能满足我们的一些日常需求外,Redisson还提供了分布式锁的解决方案,接下来我会使用RedissonClient来实现一个分布式锁来进行测试:

@Service
public class RedissonService {
    private final RedissonClient redissonClient;
    private volatile int count = 0; // 用于计数的变量
    private static final Logger logger = LoggerFactory.getLogger(RedissonService.class);
    @Autowired
    public RedissonService(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }
    public void performTest() throws InterruptedException {
        int threadNums = 100;
        CountDownLatch countDownLatch = new CountDownLatch(threadNums);

        for (int i = 0; i < threadNums; i++) {
            new Thread(() -> {
                // 使用RLock,这是Redisson的可重入锁
                RLock lock = redissonClient.getLock("counterLock");

                try {
                    // 尝试获取锁,等待获取锁最多10秒,超过10秒当前线程自动放弃;锁持有最长1秒,超时自动释放
                    if (lock.tryLock(10, 1, TimeUnit.SECONDS)) {
                        try {
                            // 计数器自增 1,通过redis锁来保证每次+1操作只有一个线程能进行
                            count += 1;
                            logger.info("计数器+1为:{}", count);
                        } finally {
                            // 释放锁
                            lock.unlock();
                        }
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt(); // 设置中断标志
                } finally {
                    // 计数器减1,直到计数器为0时
                    countDownLatch.countDown();
                }
            }).start();
        }

        countDownLatch.await(); // 等待所有线程完成,即当countDownLatch为0时完成,继续往下执行

        logger.info("count = {}", count);
    }
}

上述代码中同样使用了构造器注入的方式,将RedissonClient注入到方法中,主要需要理解下performTest()方法。

  1. 使用CountDownLatch:是为了让这100个线程全部执行完毕之后,才打印最终的计数count,不然循环中新创建的线程还没全部执行完就打印日志了,那结果肯定是不准的。
  2. 使用RLock:使用RLock而不是JUC包下的Lock,是因为RLock 是专门为使用 Redis 作为后端存储的环境设计的,用法也与Lock大差不差,但是RLock可以使用tryLock()尝试获取锁,并在规定时间内获取锁后,又会在指定时间后释放掉锁,从而避免锁得不到释放的情况。
  3. count的类型:之所以可以不用AtomicInteger来进行自增,是因为AtomicInteger更消耗时间和资源,并且最主要的是在这里不需要保证count的原子性,因为每次count的修改都只有1个线程才能对它进行修改,是通过redis的锁来实现的,当执行当前线程后释放锁,下一个线程又可以操作count了,

测试结果:

	@Test
    public void testRedisson() throws InterruptedException {
        redissonService.performTest();
    }

测试结果
当然,实现redis分布式锁的方式还有挺多,例如lua脚本: if redis.call(‘get’, KEYS[1]) == ARGV[1] then return redis.call(‘del’, KEYS[1]) else return 0 end、基于Setnx的原始实现等等,就不细聊了,有兴趣的可以多去了解下^^

总结

Spring Boot对于Redis和Redis的整合还是蛮简单方便的,总的老说就是创建了Spring Boot项目后,导入redis数据库的依赖,同时也别忘记了导入spring-boot-web的依赖,因为里面包含了redis序列话需要用到的jackson库,之后配置RedisTemplate的配置文件,后面就可以注入RedisClient进行使用啦;Redisson的话也是同理,添加redisson依赖,注入RedissonClient就可以使用啦,还是很方便的!

在这里插入图片描述

  • 15
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值