Redis(Remote Dictionary Server),作为一种高性能的内存型键值数据库,广泛应用于缓存、会话管理、消息队列和排行榜等场景。本文将系统性介绍 Redis 的基础知识、安装、核心数据结构、常用命令,以及与 Java 客户端的集成,帮助开发者快速上手。


一、认识 NoSQL

Redis 属于 NoSQL 数据库,与传统的 SQL 数据库有以下显著区别:

特性

SQL 数据库

NoSQL 数据库

数据结构

结构化(表格)

非结构化(键值对、文档等)

数据关联性

强关联性(表间关系复杂)

弱关联性(自己维护)

查询方式

SQL 语言 (统一)

非 SQL API(非统一)

事务模型

支持 ACID

多为 BASE 模型

存储方式

磁盘

内存

扩展性

垂直扩展(提升硬件性能)

水平扩展(增加节点)

NoSQL 数据库根据存储模型分为:

  • 键值型:如 Redis、Memcached。

  • 文档型:如 MongoDB。

  • 列型:如 HBase。

  • 图型:如 Neo4j。

二、认识 Redis

Redis 是一个 NoSQL 数据库,其主要特点是:

  • 基于内存:支持超低延迟的读写操作。

  • 键值存储:以 Key-Value 形式存储数据,同时支持多种 Value 数据类型。

  • 单线程架构:采用 IO 多路复用技术实现高效并发。

  • 支持持久化:提供 RDB 快照和 AOF 日志两种持久化方式。

  • 分布式支持:支持主从复制、哨兵模式和分片集群。

  • 多语言客户端:支持 Java、Python、Go 等主流编程语言。

Redis 的应用场景

  1. 缓存系统:如用户会话缓存、热点数据缓存。

  2. 排行榜:借助 SortedSet 实现分数排序。

  3. 分布式锁:通过 SetNX 和过期时间实现简单高效的分布式锁。

  4. 消息队列:利用 List 的阻塞特性模拟生产者-消费者模型。

  5. 地理位置服务:通过 Geo 类型存储地理信息。

三、Redis 安装详解

Redis 官方仅提供 Linux 环境下的安装包,本指南以 CentOS 7 为例。

1. 安装 Redis 依赖

Redis 使用 C 语言编写,需要安装 gcctcl 依赖:

yum install -y gcc tcl

2. 上传并解压安装包

将 Redis 安装包上传至服务器指定目录(如 /usr/local/src)并解压:

tar -xzf redis-6.2.6.tar.gz
cd redis-6.2.6
make && make install

解压后,Redis 会默认安装到 /usr/local/bin

3. 启动 Redis

Redis 提供多种启动方式:

  • 默认启动:前台运行,不推荐,关闭会话窗口会导致服务终止。

    redis-server
  • 指定配置文件启动:修改 redis.conf 配置后,可实现后台运行。

    redis-server /path/to/redis.conf

    Redis主要配置:

    # 允许外部访问:默认仅支持本地访问
    bind 0.0.0.0
    
    # 守护进程,修改为yes后即可后台运行
    daemonize yes 
    
    # 密码,设置后访问Redis必须输入密码
    requirepass 123321
    
    
    
    

    Redis的其他常见配置:

    # 监听的端口
    port 6379
    # 工作目录,默认是当前目录,也就是运行redis-server时的命令,日志、持久化等文件会保存在这个目录
    dir .
    # 数据库数量,设置为1
    # 代表只使用1个库,默认有16个库,编号0~15
    databases 1
    # 设置redis能够使用的最大内存
    maxmemory 512mb
    # 日志文件,默认为空,不记录日志,可以指定日志文件名
    logfile "redis.log"
  • 开机自启:通过创建系统服务文件实现:

    vi /etc/systemd/system/redis.service

    配置文件内容示例:

    [Unit]
    Description=redis-server
    After=network.target
    ​
    [Service]
    Type=forking
    ExecStart=/usr/local/bin/redis-server /path/to/redis.conf
    PrivateTmp=true
    ​
    [Install]
    WantedBy=multi-user.target

    启用服务:

    systemctl daemon-reload
    systemctl enable redis
    systemctl start redis

四、Redis 的客户端工具

1. 命令行客户端

Redis 自带 redis-cli 工具,可执行交互式命令操作:

redis-cli -h 127.0.0.1 -p 6379 -a yourpassword

常见操作命令:

  • PING:心跳测试,服务正常返回 PONG

  • SELECT:切换数据库,SELECT 0 表示切换到第 0 号数据库。

2. 图形化客户端

Redis未提供官方图形客户端,推荐使用 RedisDesktopManager,它提供直观的操作界面:

  • 安装包下载地址:GitHub

  • 安装后运行 rdm.exe,配置连接信息即可使用。


五 、Redis 的五种数据结构

Redis 提供了丰富的数据结构以适配不同场景需求,其提供了五种基本类型和一些基于基本类型衍生出来的特殊类型,这里我们先了解前五个最常用的基本类型。

redis-dataStructure.png

Redis为了方便我们学习,将操作不同数据类型的命令也做了分组,在官网( Commands | Docs)可以查看到不同的命令,下面只讲解常用的基本命令,更多命令大家需自行查阅:

0. 通用命令

通用指令是不分数据类型的,都可以使用的指令,常见的有:

## 1. 键(key)操作相关命令
KEYS pattern                 # 查看符合模板的所有key, 不建议在生产环境上使用
SET key value                # 设置键 key 的值为 value
GET key                      # 获取键 key 的值
DEL key [key ...]            # 删除一个或多个键
EXISTS key [key ...]         # 检查一个或多个键是否存在,返回存在键的数量
EXPIRE key seconds           # 设置键的过期时间为指定的秒数
TTL key                      # 获取键的剩余生存时间,单位为秒
RENAME key newkey            # 重命名键 key 为 newkey
TYPE key                     # 返回键的值类型(如 string、list、set 等)

## 2. 服务器管理命令
INFO                            # 获取 Redis 服务器信息和统计数据
PING                            # 测试服务器连通性,返回 PONG
FLUSHALL                        # 清空整个 Redis 数据库
FLUSHDB                         # 清空当前数据库中的数据
CONFIG GET parameter            # 获取 Redis 配置参数
CONFIG SET parameter value      # 设置 Redis 配置参数

1. String 类型

最基础的数据类型,支持字符串、整数和浮点数。 示例操作:

SET key value                # 设置键值对
GET key                      # 获取键的值
MSET key value [key value]   # 批量设置多个键值对
MGET key [key ...]           # 批量获取多个键的值
INCR key                     # 整型键值自增 1
INCRBY key increment         # 整型键值按指定步长自增
INCRBYFLOAT key increment    # 浮点型键值按指定步长自增
SETNX key value              # 设置键值对,仅当键不存在
SETEX key seconds value      # 设置键值对并指定过期时间(秒)

应用场景

  • 缓存简单对象,如用户信息。

  • 分布式计数器。


2. Hash 类型

类似 Java 的 HashMap,支持对字段进行独立操作。 示例操作:

HSET key field value         # 设置或修改 Hash 键中指定字段的值
HGET key field               # 获取 Hash 键中指定字段的值
HMSET key field value [...]  # 批量设置 Hash 键中多个字段的值
HMGET key field [...]        # 批量获取 Hash 键中多个字段的值
HGETALL key                  # 获取 Hash 键中所有字段和对应的值
HKEYS key                    # 获取 Hash 键中的所有字段
HVALS key                    # 获取 Hash 键中的所有值
HINCRBY key field increment  # Hash 键字段值按指定步长自增
HSETNX key field value       # 设置 Hash 键字段的值,仅当字段不存在

应用场景

  • 存储用户信息等复杂对象。


3. List 类型

双向链表,支持正序和倒序操作。 示例操作:

LPUSH key element [...]       # 向列表左侧插入一个或多个元素
LPOP key                      # 移除并返回列表左侧第一个元素
RPUSH key element [...]       # 向列表右侧插入一个或多个元素
RPOP key                      # 移除并返回列表右侧第一个元素
LRANGE key start end          # 获取列表指定范围内的所有元素
BLPOP key [key ...] timeout   # 阻塞移除并返回左侧第一个元素,超时返回 nil
BRPOP key [key ...] timeout   # 阻塞移除并返回右侧第一个元素,超时返回 nil

应用场景

  • 消息队列。

  • 排队功能。


4. Set 类型

无序集合,支持去重和集合运算。 示例操作:

SADD key member [...]       # 向集合中添加一个或多个元素
SREM key member [...]       # 移除集合中的指定元素
SCARD key                   # 返回集合中元素的个数
SISMEMBER key member        # 判断元素是否存在于集合中
SMEMBERS key                # 获取集合中的所有元素
SINTER key1 key2 [...]      # 求多个集合的交集
SDIFF key1 key2 [...]       # 求多个集合的差集
SUNION key1 key2 [...]      # 求多个集合的并集

应用场景

  • 计算共同好友、唯一访问者等。


5. SortedSet 类型

有序集合,基于 Score 排序。 示例操作:

ZADD key score member [...]                        # 添加或更新元素及其 score
ZREM key member [...]                              # 删除指定元素
ZSCORE key member                                  # 获取指定元素的 score 值
ZRANK key member                                   # 获取指定元素的排名(升序)
ZCARD key                                          # 获取集合中的元素个数
ZCOUNT key min max                                 # 统计 score 在指定范围内的元素个数
ZINCRBY key increment member                       # 指定元素的 score 自增
ZRANGE key start stop [WITHSCORES]                 # 获取指定排名范围内的元素(升序)
ZRANGEBYSCORE key min max [LIMIT offset count]     # 获取指定 score 范围内的元素
ZDIFF numkeys key [key ...]                        # 求多个集合的差集
ZINTER numkeys key [key ...]                       # 求多个集合的交集
ZUNION numkeys key [key ...]                       # 求多个集合的并集
ZREVRANGE key start stop [WITHSCORES]              # 获取指定排名范围内的元素(降序)
ZRANGEBYSCORE key max min REV                      # 获取指定 score 范围内的元素(降序)

应用场景

  • 排行榜。

  • 带优先级的任务队列。

Redis key的最佳实践:

Redis的key允许有多个单词形成层级结构,多个单词之间用':'隔开,格式如下:

redis-key-suggestion.png

这个格式并非固定,也可以根据自己的需求来删除或添加词条。

例如我们的项目名称叫 alibaba,有user和product两种不同类型的数据,我们可以这样定义key:

  • user相关的key:alibaba:user:1

  • product相关的key:alibaba:product:1

如果Value是一个Java对象,例如一个User对象,则可以将对象序列化为JSON字符串后存储:

redis-save-UserPO.png


六、Redis 的 Java 客户端

在Redis官网中提供了各种语言的客户端,地址:Connect with Redis client API libraries | Docs。不过实际开发中,我们一般使用Spring Data Redis,其提供了不同Redis客户端的整合(Lettuce和Jedis)

1. Jedis 快速入门

Jedis的官网地址:GitHub - redis/jedis: Redis Java client, 我们先来快速入个门:

  • 添加 Maven 依赖:

    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>3.7.0</version>
    </dependency>
  • 建立连接:

    Jedis jedis = new Jedis("localhost", 6379);
    jedis.auth("password");
    jedis.set("name", "Tiger");
    System.out.println(jedis.get("name"));
    jedis.close();
  • Jedis本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗,因此我们推荐大家使用Jedis连接池代替Jedis的直连方式。

    import redis.clients.jedis.*;
    
    public class JedisConnectionFactory {
    
        private static final JedisPool jedisPool;
    
        static {
            JedisPoolConfig config = new JedisPoolConfig();
            config.setMaxTotal(8); // 最大连接数
            config.setMaxIdle(8);  // 最大空闲连接数
            config.setMinIdle(0);  // 最小空闲连接数
            config.setMaxWaitMillis(200); // 最大等待时间(毫秒)
            
            // 初始化连接池
            jedisPool = new JedisPool(config, "192.168.150.101", 6379, 1000, "123321"); 
        }
    
        public static Jedis getJedis() {
            return jedisPool.getResource(); // 获取 Jedis 实例
        }
    }

2. Spring Data Redis 快速入门

SpringDataRedis中提供了RedisTemplate工具类,其中封装了各种对Redis的操作。并且将不同数据类型的操作API封装到了不同的类型中,官网地址:Spring Data Redis

  • 配置依赖:

    <!-- Redis 依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    
    <!-- Commons Pool 连接池依赖 -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
    </dependency>
  • 配置文件:

    spring:
      redis:
        host: 192.168.150.101 # Redis 主机地址
        port: 6379           # Redis 端口号
        password: 123321     # Redis 密码
        lettuce:
          pool:
            max-active: 8    # 最大连接数
            max-idle: 8      # 最大空闲连接数
            min-idle: 0      # 最小空闲连接数
            max-wait: 100    # 连接最大等待时间(毫秒)
  • 使用 RedisTemplate 操作 Redis:

    @SpringBootTest
    public class RedisTest {
        @Autowired
        private RedisTemplate<String, Object> redisTemplate;
    
        @Test
        void testString() {
            // 插入和读取 string 类型数据
            redisTemplate.opsForValue().set("name", "李四");
            Object name = redisTemplate.opsForValue().get("name");
            System.out.println("name = " + name);
        }
    }

RedisTemplate 的两种序列化实践方案

RedisTemplate可以接收任意Object作为值写入Redis,只不过写入前会把Object序列化为字节形式,默认是采用JDK序列化,得到的结果是这样的:

缺点:可读性差、内存占用较大

方案一:自定义 RedisTemplate

  • 修改 RedisTemplate 的序列化器为 GenericJackson2JsonRedisSerializer

  • 实现全局统一的序列化和反序列化规则,适用于复杂对象的存储和操作。

我们可以自定义RedisTemplate的序列化方式,代码如下:

@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
    RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
    
    // 设置连接工厂
    redisTemplate.setConnectionFactory(redisConnectionFactory);
    
    // 配置序列化器
    GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
    redisTemplate.setKeySerializer(RedisSerializer.string()); // key 和 hashKey 使用 String 序列化
    redisTemplate.setHashKeySerializer(RedisSerializer.string());
    redisTemplate.setValueSerializer(jsonRedisSerializer);    // value 和 hashValue 使用 JSON 序列化
    redisTemplate.setHashValueSerializer(jsonRedisSerializer);
    
    return redisTemplate;
}

尽管JSON的序列化方式可以满足我们的需求,但依然存在一些问题,如图:

为了在反序列化时知道对象的类型,JSON序列化器会将类的class类型写入json结果中,存入Redis,会带来额外的内存开销。

方案二:使用 StringRedisTemplate

  • 为了节省内存空间,我们并不会使用JSON序列化器来处理value,而是统一使用String序列化器,要求只能存储String类型的key和value。当需要存储Java对象时,手动完成对象的序列化和反序列化。

  • Spring默认提供了一个StringRedisTemplate类,它的key和value的序列化方式默认就是String方式。省去了我们自定义RedisTemplate的过程:

  • 写入 Redis 时,手动将对象序列化为 JSON。

  • 读取 Redis 时,手动将 JSON 数据反序列化为对象。

public class RedisTest {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    // JSON 工具类
    private static final ObjectMapper mapper = new ObjectMapper();

    @Test
    void testStringTemplate() throws JsonProcessingException {
        // 创建 User 对象并手动序列化为 JSON
        User user = new User("Java之父马士兵", 18);
        String json = mapper.writeValueAsString(user);
        
        // 写入 Redis 数据
        stringRedisTemplate.opsForValue().set("user:200", json);

        // 从 Redis 读取数据并反序列化
        String val = stringRedisTemplate.opsForValue().get("user:200");
        User user1 = mapper.readValue(val, User.class);
        
        // 输出反序列化后的 User 对象
        System.out.println("user1 = " + user1);
    }
}

七、总结

Redis 是一款功能强大、性能卓越的 NoSQL 数据库,适用于多种场景。通过本指南,您可以快速掌握 Redis 的核心功能及其在 Java 开发中的应用。继续深入学习,您还可以探索 Redis 的高级特性如主从复制、哨兵模式和集群模式,打造更加高效的分布式系统。

Redis,赋能数据存储的最佳选择!


如果需要代码示例和更多高级操作,欢迎留言或查阅 Redis 官方文档!