在高并发场景中,传统数据库往往面临读写压力过大的问题。Redis(Remote Dictionary Server)作为一款高性能的内存数据库,凭借其快读写、多数据结构、支持持久化等特性,成为缓存、分布式锁、计数器等场景的首选工具。本文将从 Redis 核心概念出发,结合 Java 实战,带你快速掌握 Redis 的入门用法。

一、Redis 核心概念

在使用 Redis 前,需先理解其核心特性和数据模型,这是后续实战的基础。

1. 核心特性

  • 内存存储:数据主要存于内存,读写速度极快(单机 QPS 可达 10 万+)。
  • 多数据结构:支持 String(字符串)、Hash(哈希)、List(列表)、Set(集合)、Sorted Set(有序集合)等多种结构。
  • 持久化:支持 RDB(快照)和 AOF(日志)两种持久化方式,避免内存数据丢失。
  • 高可用:支持主从复制、哨兵模式、集群模式,保证服务稳定。
  • 原子操作:提供incr、decr等原子命令,适合实现计数器、分布式锁等场景。

2. 核心数据结构

Redis 的核心价值在于丰富的数据结构,不同结构对应不同场景,新手需重点掌握以下 5 种:

数据结构特点适用场景
String(字符串)最基础类型,可存储文本、数字,支持拼接、截取缓存用户信息、存储计数器、分布式 ID
Hash(哈希)键值对集合,适合存储对象(如用户信息)缓存用户详情、商品信息
List(列表)有序、可重复的元素集合,支持两端操作实现消息队列、最新消息列表
Set(集合)无序、不可重复的元素集合,支持交集、并集好友关系、标签去重、共同关注
Sorted Set(有序集合)有序、不可重复,元素关联“分数”排序排行榜、带权重的消息队列

二、环境准备

1. 安装 Redis

推荐使用 Docker 快速部署(本地安装需手动配置,步骤较繁琐):

# 拉取 Redis 镜像(6.2 版本为例,稳定且常用)
docker pull redis:6.2

# 启动容器(映射 6379 端口,设置密码为 123456)
docker run -d --name redis -p 6379:6379 redis:6.2 --requirepass "123456"

启动后,可通过 redis-cli 测试连接(需先进入容器):

# 进入 Redis 容器
docker exec -it redis /bin/bash
# 连接 Redis 服务(输入密码 123456)
redis-cli -a 123456
# 测试命令(返回 PONG 说明连接成功)
ping

2. 引入 Java 客户端依赖

Java 操作 Redis 最常用的客户端是 Jedis(轻量、易用)和 Spring Data Redis(集成 Spring,简化开发)。本文先以 Jedis 为例,后续补充 Spring 集成方案。

在 Maven 项目的 pom.xml 中添加 Jedis 依赖:

<!-- Jedis 客户端依赖 -->
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>3.7.0</version>
</dependency>
<!-- 测试依赖(可选,用于编写测试用例) -->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>5.8.1</version>
    <scope>test</scope>
</dependency>

3. 初始化 Jedis 连接

创建 RedisClient 工具类,封装 Jedis 连接的初始化和关闭(实际项目中建议用连接池,避免频繁创建连接):

import redis.clients.jedis.Jedis;

public class RedisClient {
    // Redis 服务地址和端口
    private static final String HOST = "localhost";
    private static final int PORT = 6379;
    // Redis 密码
    private static final String PASSWORD = "123456";

    // 获取 Jedis 连接
    public static Jedis getConnection() {
        // 1. 创建连接
        Jedis jedis = new Jedis(HOST, PORT);
        // 2. 验证密码
        jedis.auth(PASSWORD);
        // 3. 选择数据库(默认 0 号库,共 16 个库,0-15)
        jedis.select(0);
        return jedis;
    }

    // 关闭连接
    public static void closeConnection(Jedis jedis) {
        if (jedis != null) {
            jedis.close();
        }
    }
}
注意:实际项目中需使用 Jedis 连接池JedisPool),避免频繁创建/关闭连接导致性能损耗,下文会补充连接池配置。

三、Java 操作 Redis 实战

以“电商缓存”场景为例,演示 5 种核心数据结构的常用操作。

1. String 类型:缓存商品名称与计数器

String 是 Redis 最基础的类型,可存储文本或数字,支持 set(存值)、get(取值)、incr(自增)等命令。

import org.junit.jupiter.api.Test;
import redis.clients.jedis.Jedis;

public class RedisStringTest {

    @Test
    public void testStringOps() {
        // 1. 获取连接
        Jedis jedis = RedisClient.getConnection();

        try {
            // (1)存储商品名称(key:product:name:1,value:华为 Mate 60)
            jedis.set("product:name:1", "华为 Mate 60");
            System.out.println("商品名称:" + jedis.get("product:name:1"));

            // (2)存储商品库存(数字类型,支持自增自减)
            jedis.set("product:stock:1", "100");  // 初始库存 100
            jedis.incr("product:stock:1");  // 库存 +1(变为 101)
            jedis.decrBy("product:stock:1", 5);  // 库存 -5(变为 96)
            System.out.println("商品库存:" + jedis.get("product:stock:1"));

            // (3)设置过期时间(10 秒后自动删除,适合临时缓存)
            jedis.setex("product:temp:1", 10, "临时缓存数据");
            System.out.println("临时缓存剩余时间(秒):" + jedis.ttl("product:temp:1"));

        } finally {
            // 2. 关闭连接(避免资源泄漏)
            RedisClient.closeConnection(jedis);
        }
    }
}

2. Hash 类型:缓存用户详情

Hash 适合存储“对象”(如用户、商品),可单独操作某个字段(无需修改整个对象),节省内存和带宽。

import org.junit.jupiter.api.Test;
import redis.clients.jedis.Jedis;
import java.util.Map;

public class RedisHashTest {

    @Test
    public void testHashOps() {
        Jedis jedis = RedisClient.getConnection();

        try {
            // (1)存储用户详情(key:user:1,字段:name/age/phone)
            jedis.hset("user:1", "name", "张三");
            jedis.hset("user:1", "age", "25");
            jedis.hset("user:1", "phone", "13800138000");

            // (2)获取单个字段(用户姓名)
            System.out.println("用户姓名:" + jedis.hget("user:1", "name"));

            // (3)获取所有字段和值(完整用户信息)
            Map<String, String> userMap = jedis.hgetAll("user:1");
            System.out.println("完整用户信息:" + userMap);

            // (4)删除某个字段(删除用户手机号)
            jedis.hdel("user:1", "phone");
            System.out.println("删除手机号后:" + jedis.hgetAll("user:1"));

        } finally {
            RedisClient.closeConnection(jedis);
        }
    }
}

3. List 类型:实现简单消息队列

List 是有序、可重复的集合,支持 lpush(左插)、rpop(右取)等命令,适合实现“先进先出”(FIFO)的消息队列。

import org.junit.jupiter.api.Test;
import redis.clients.jedis.Jedis;

public class RedisListTest {

    @Test
    public void testListOps() {
        Jedis jedis = RedisClient.getConnection();

        try {
            // 队列 key:order:queue(存储订单 ID)
            String queueKey = "order:queue";

            // (1)生产者:向左插入 3 个订单 ID(模拟下单)
            jedis.lpush(queueKey, "order1001", "order1002", "order1003");
            System.out.println("队列长度:" + jedis.llen(queueKey));  // 输出 3

            // (2)消费者:向右取出订单 ID(模拟处理订单)
            String orderId1 = jedis.rpop(queueKey);
            String orderId2 = jedis.rpop(queueKey);
            System.out.println("处理的订单:" + orderId1 + "、" + orderId2);
            System.out.println("剩余队列长度:" + jedis.llen(queueKey));  // 输出 1

            // (3)查看队列所有元素
            System.out.println("剩余订单:" + jedis.lrange(queueKey, 0, -1));

        } finally {
            RedisClient.closeConnection(jedis);
        }
    }
}

4. Set 类型:实现用户标签去重

Set 是无序、不可重复的集合,支持交集、并集、差集等操作,适合标签去重、好友关系管理。

import org.junit.jupiter.api.Test;
import redis.clients.jedis.Jedis;
import java.util.Set;

public class RedisSetTest {

    @Test
    public void testSetOps() {
        Jedis jedis = RedisClient.getConnection();

        try {
            // (1)存储用户 1 的标签(key:user:tags:1)
            jedis.sadd("user:tags:1", "足球", "篮球", "游戏");
            // 存储用户 2 的标签(key:user:tags:2)
            jedis.sadd("user:tags:2", "篮球", "音乐", "电影");

            // (2)获取用户 1 的所有标签(自动去重)
            Set<String> user1Tags = jedis.smembers("user:tags:1");
            System.out.println("用户 1 标签:" + user1Tags);

            // (3)判断用户 1 是否有“游戏”标签
            boolean hasGameTag = jedis.sismember("user:tags:1", "游戏");
            System.out.println("用户 1 有游戏标签:" + hasGameTag);  // 输出 true

            // (4)求两个用户的共同标签(交集)
            Set<String> commonTags = jedis.sinter("user:tags:1", "user:tags:2");
            System.out.println("共同标签:" + commonTags);  // 输出 [篮球]

        } finally {
            RedisClient.closeConnection(jedis);
        }
    }
}

5. Sorted Set 类型:实现商品销量排行榜

Sorted Set 与 Set 类似,但每个元素关联一个“分数”(score),按分数自动排序,适合实现排行榜、带权重的队列。

import org.junit.jupiter.api.Test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Tuple;
import java.util.Set;

public class RedisSortedSetTest {

    @Test
    public void testSortedSetOps() {
        Jedis jedis = RedisClient.getConnection();

        try {
            // 排行榜 key:product:sales:rank(按销量排序)
            String rankKey = "product:sales:rank";

            // (1)存储商品销量(商品 ID 为元素,销量为分数)
            jedis.zadd(rankKey, 1000, "product1001");  // 商品 1 销量 1000
            jedis.zadd(rankKey, 2500, "product1002");  // 商品 2 销量 2500
            jedis.zadd(rankKey, 1800, "product1003");  // 商品 3 销量 1800

            // (2)获取销量前 2 的商品(降序排列,0 表示第 1 名,1 表示第 2 名)
            Set<Tuple> top2 = jedis.zrevrangeWithScores(rankKey, 0, 1);
            System.out.println("销量前 2 商品:");
            for (Tuple tuple : top2) {
                System.out.println("商品 ID:" + tuple.getElement() + ",销量:" + tuple.getScore());
            }

            // (3)获取商品 3 的销量排名(降序,返回排名索引,从 0 开始)
            long rank = jedis.zrevrank(rankKey, "product1003");
            System.out.println("商品 3 销量排名:第 " + (rank + 1) + " 名");  // 输出第 2 名

        } finally {
            RedisClient.closeConnection(jedis);
        }
    }
}

四、进阶:Jedis 连接池配置

前文的简单连接方式不适合高并发场景,需使用 JedisPool(连接池)管理连接,减少连接创建/关闭的开销。

1. 配置连接池

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public class RedisPoolClient {
    // 连接池配置
    private static final JedisPoolConfig POOL_CONFIG;
    // 连接池实例(单例)
    private static final JedisPool JEDIS_POOL;

    // 静态代码块:初始化连接池
    static {
        // 1. 配置连接池参数
        POOL_CONFIG = new JedisPoolConfig();
        POOL_CONFIG.setMaxTotal(20);  // 最大连接数
        POOL_CONFIG.setMaxIdle(10);   // 最大空闲连接数
        POOL_CONFIG.setMinIdle(5);    // 最小空闲连接数
        POOL_CONFIG.setTestOnBorrow(true);  // 借连接时测试可用性

        // 2. 初始化连接池
        JEDIS_POOL = new JedisPool(
            POOL_CONFIG,
            "localhost",  // 地址
            6379,         // 端口
            10000,        // 连接超时时间(毫秒)
            "123456"      // 密码
        );
    }

    // 从连接池获取连接
    public static Jedis getConnection() {
        return JEDIS_POOL.getResource();
    }

    // 关闭连接(实际是归还到连接池)
    public static void closeConnection(Jedis jedis) {
        if (jedis != null) {
            jedis.close();
        }
    }
}

2. 使用连接池

后续操作只需替换 RedisClientRedisPoolClient 即可,用法完全一致:

// 从连接池获取连接
Jedis jedis = RedisPoolClient.getConnection();
try {
    // 执行 Redis 命令(如 set、get 等)
} finally {
    // 归还连接到池
    RedisPoolClient.closeConnection(jedis);
}

五、入门必备:常见问题与最佳实践

1. 键名设计规范

  • 使用冒号分隔层级:如 product:name:1(业务:字段:ID),便于区分和管理。
  • 避免过长键名:键名会占用内存,建议简洁(如用 user:1 而非 user_info_123)。
  • 统一命名风格:全小写,避免特殊字符,保持团队一致。

2. 避免数据丢失:持久化配置

Redis 内存数据默认不持久化,需手动开启 RDB 或 AOF:

  • RDB:定期生成内存快照(适合数据恢复,但可能丢失少量数据)。
  • AOF:记录每一条写命令(数据更安全,但文件

本文作者:
文章标签:Java数据库指南服务治理Redis
文章标题:Java 实现 Redis 入门指南:从概念到实战
本文地址:https://www.ducky.vip/archives/redis.html
版权说明:若无注明,本文皆 iDuckie's Blog 原创,转载请保留文章出处。
最后修改:2025 年 11 月 01 日
如果觉得我的文章对你有用,请随意赞赏