Redis入门
Redis入门
redis为一种基于内存的key-value的数据库(内存存储)(sql为磁盘二维表存储) 读写性能高 存热点数据(内存不大)互补的
启动命令
D:\Develop\redis>redis-server.exe redis.windows.conf
中止快捷键ctrl+c
_.__.-``__ ''-.__.-`` `. `_. ''-._ Redis 3.2.100 (00000000/0) 64 bit.-`` .-```. ```\/ _.,_ ''-._( ' , .-` | `, ) Running in standalone mode|`-._`-...-` __...-.``-._|'` _.-'| Port: 6379| `-._ `._ / _.-' | PID: 26232`-._ `-._ `-./ _.-' _.-'|`-._`-._ `-.__.-' _.-'_.-'|| `-._`-._ _.-'_.-' | http://redis.io`-._ `-._`-.__.-'_.-' _.-'|`-._`-._ `-.__.-' _.-'_.-'|| `-._`-._ _.-'_.-' |`-._ `-._`-.__.-'_.-' _.-'`-._ `-.__.-' _.-'`-._ _.-'`-.__.-'[26232] 14 Apr 14:19:05.925 # Server started, Redis version 3.2.100
[26232] 14 Apr 14:19:05.926 * The server is now ready to accept connections on port 6379
[26232] 14 Apr 14:19:20.449 # User requested shutdown...
[26232] 14 Apr 14:19:20.450 * Saving the final RDB snapshot before exiting.
[26232] 14 Apr 14:19:20.450 # Failed opening the RDB file dump.rdb (in server root dir D:\Develop\redis) for saving: Permission denied
[26232] 14 Apr 14:19:20.450 # Error trying to save the DB, can't exit.
[26232] 14 Apr 14:19:20.450 # SIGTERM received but errors trying to shut down the server, check the logs for more information
redis数据类型
5种数据类型(value)
Redis 作为一款高性能的内存键值数据库,其丰富的数据结构是支撑其广泛应用场景的关键。对于 Java 开发者而言,理解 Redis 的核心数据类型是高效使用 Redis 的第一步。幸运的是,Redis 的许多数据结构在概念上与 Java 集合框架(Java Collection Framework, JCF)中的容器有相似之处。本文旨在通过与 JCF 的类比,帮助 Java 开发者更直观、深入地理解 Redis 的五种基本数据类型:String、List、Hash、Set 和 Sorted Set (ZSet)。
注意: 类比有助于理解,但务必认识到 Redis 与 Java 在运行环境(网络、内存管理、持久化)和操作特性(原子性、服务器端计算)上的本质区别。
1. Redis String (字符串) <=> Java String
/ 基本类型包装类
- Redis String:
- 描述: Redis 中最基础的数据类型,可以存储字符串、整数或者浮点数,甚至是二进制数据(最大 512MB)。
- 特点: 值是原子操作的基础(如
INCR
,DECR
),可以进行位操作(GETBIT
,SETBIT
)。
- Java 类比:
java.lang.String
或基本数据类型的包装类 (Integer
,Long
,Double
, etc.)- 相似点: 概念上最接近,用于存储单个值。一个 Redis Key 对应一个 String Value,就像一个 Java 变量名对应一个 String 对象或数值。
- 差异与注意:
- 原子性: Redis 的
INCR
/DECR
等命令是原子性的,由 Redis 服务器保证,这对于分布式计数器等场景非常关键。Java 中对包装类的i++
操作在并发环境下并非原子操作,需要AtomicInteger
等原子类。 - 类型: Redis String 内部存储的是字节序列,可以是文本或二进制。Java
String
是 UTF-16 编码的字符序列,基本类型有明确的数值类型。 - 可变性: Java
String
是不可变的,而 Redis String 可以通过APPEND
,SETRANGE
等命令进行修改。
- 原子性: Redis 的
- Redis 用例: 缓存用户信息、Session、计数器、分布式锁、存储配置信息等。
2. Redis List (列表) <=> Java java.util.LinkedList
(Deque
/List
)
- Redis List:
- 描述: 一个双向链表结构,存储有序的字符串元素,允许重复。可以在列表的两端进行 O(1) 时间复杂度的插入(
LPUSH
,RPUSH
)和弹出(LPOP
,RPOP
)操作。 - 特点: 保持插入顺序,支持按下标范围获取元素(
LRANGE
,但非两端操作复杂度较高)。
- 描述: 一个双向链表结构,存储有序的字符串元素,允许重复。可以在列表的两端进行 O(1) 时间复杂度的插入(
- Java 类比:
java.util.LinkedList
- 相似点:
LinkedList
同时实现了List
和Deque
接口,其双向链表的底层实现使得在头尾添加/删除元素非常高效(O(1)),这与 Redis List 的核心特性高度吻合。可以模拟队列(FIFO,RPUSH
/LPOP
)或栈(LIFO,LPUSH
/LPOP
)。 - 差异与注意:
- 阻塞操作: Redis List 提供阻塞式弹出命令(
BLPOP
,BRPOP
),可以用于实现可靠的消息队列,Java 标准库的LinkedList
本身不直接提供阻塞功能(需要BlockingQueue
实现类)。 - 内存与性能: Redis List 在元素较少时会使用 ziplist/listpack 优化存储,节省内存。Java
LinkedList
的每个节点都有额外的指针开销。 - 内容: Redis List 存储的是字符串,Java
LinkedList
可以存储任意对象引用。
- 阻塞操作: Redis List 提供阻塞式弹出命令(
- 相似点:
- Redis 用例: 消息队列、任务队列、用户动态 Feed 流、最新消息列表、排行榜(简单场景,非实时精确排序)。
3. Redis Hash (哈希/字典) <=> Java java.util.HashMap
- Redis Hash:
- 描述: 存储字段(field)和值(value)的映射集合。一个 Redis Key 对应一个 Hash 结构,该结构内包含多个 field-value 对。Field 不允许重复。
- 特点: 适合存储对象结构,可以对单个字段进行读写操作(
HGET
,HSET
),比序列化整个对象存入 String 更高效、灵活。
- Java 类比:
java.util.HashMap<String, String>
(简化) 或java.util.HashMap<String, Object>
(概念)- 相似点: 核心都是键值对存储。Redis Hash 的 field 相当于
HashMap
的 key,Redis Hash 的 value 相当于HashMap
的 value。 - 差异与注意:
- 类型: Redis Hash 的 field 和 value 都是字符串。
HashMap
的 key 和 value 可以是任意 Java 对象。 - 存储效率: Redis Hash 在 field 数量和 value 大小适中时,内部可能使用 ziplist/listpack 编码,内存占用更优。
- 操作: Redis Hash 的操作如
HINCRBY
是原子性的。HashMap
操作需要外部同步机制保证并发安全。 - 适用场景: Redis Hash 非常适合存储需要频繁读写部分属性的对象,避免了序列化/反序列化的开销和只读写部分数据带来的网络流量。
- 类型: Redis Hash 的 field 和 value 都是字符串。
- 相似点: 核心都是键值对存储。Redis Hash 的 field 相当于
- Redis 用例: 存储用户对象的属性(用户名、年龄、邮箱等)、商品信息、购物车条目。
4. Redis Set (集合) <=> Java java.util.HashSet
- Redis Set:
- 描述: 无序的、唯一的字符串元素集合。不允许重复元素。
- 特点: 支持高效的成员检查(
SISMEMBER
),并提供强大的服务器端集合运算能力(交集SINTER
, 并集SUNION
, 差集SDIFF
)。
- Java 类比:
java.util.HashSet<String>
- 相似点: 两者都保证元素的唯一性,并且通常不保证元素的顺序(Java
HashSet
的迭代顺序可能受插入顺序和哈希冲突影响,但不保证稳定)。 - 差异与注意:
- 集合运算: Redis Set 的最大优势在于其服务器端原子性的集合运算。Java 中要实现类似功能,通常需要将集合数据拉到客户端进行计算,涉及网络传输和客户端资源消耗。
- 随机获取: Redis Set 提供
SRANDMEMBER
(随机获取一个或多个元素)和SPOP
(随机移除并返回一个或多个元素)命令。
- 相似点: 两者都保证元素的唯一性,并且通常不保证元素的顺序(Java
- Redis 用例: 标签系统(给用户、文章打标签)、共同好友/关注计算、唯一访客统计(IP 地址去重)、抽奖系统。
5. Redis Sorted Set (ZSet / 有序集合) <=> Java java.util.TreeMap
/ java.util.TreeSet
(结合 Score)
- Redis Sorted Set (ZSet):
- 描述: 与 Set 类似,是有序的、唯一的字符串元素集合。特殊之处在于,每个元素都关联一个浮点数类型的分数(score),Redis 根据 score 对元素进行排序。
- 特点: 元素唯一,但 score 可以重复。支持按 score 范围 (
ZRANGEBYSCORE
) 或排名范围 (ZRANGE
) 高效查找,支持获取元素排名 (ZRANK
) 和分数 (ZSCORE
)。
- Java 类比:
TreeMap<Double, Set<String>>
或TreeSet<Element>
(其中 Element 根据 score 实现 Comparable) 或java.util.NavigableMap
/NavigableSet
- 相似点: 核心是维护一组有序的、唯一的元素。
TreeSet
基于元素的自然顺序或Comparator
排序,TreeMap
基于 key 的顺序。可以模拟 ZSet 的 score 排序特性。 - 差异与注意:
- 结构: ZSet 的 score 和 member 是直接关联的。用
TreeMap<Double, Set<String>>
模拟时,如果多个 member 具有相同的 score,需要一个 Set 来存储。用TreeSet<Element>
模拟时,需要设计一个包含 member 和 score 的Element
类,并实现其比较逻辑。 - 操作效率: Redis ZSet 对排名查询 (
ZRANK
)、范围查询 (ZRANGE
,ZRANGEBYSCORE
) 等操作有专门优化(通常是 O(log N) 或 O(log N + M) 复杂度)。Java 中虽然TreeMap
/TreeSet
也能实现范围查询,但获取排名等操作可能不那么直接或高效。 - Score 类型: Redis ZSet 的 score 是
double
类型。
- 结构: ZSet 的 score 和 member 是直接关联的。用
- 相似点: 核心是维护一组有序的、唯一的元素。
- Redis 用例: 排行榜(游戏积分、热销商品、带权重的任务)、范围查询(查找指定分数区间的用户)、优先级队列、时间轴(用时间戳作为 score)。
redis常用命令
Key (键) 相关命令
KEYS pattern
: 查找所有符合给定模式pattern
的 key (生产环境慎用)。EXISTS key [key ...]
: 检查一个或多个 key 是否存在。DEL key [key ...]
: 删除一个或多个 key。TYPE key
: 返回 key 所储存的值的数据类型 (string, list, hash, set, zset)。EXPIRE key seconds
: 为 key 设置指定的过期时间 (秒)。TTL key
: 返回 key 剩余的过期时间 (秒),-1 表示永不过期,-2 表示 key 不存在。RENAME key newkey
: 修改 key 的名称。MOVE key db
: 将当前数据库的 key 移动到给定的数据库db
当中。
二、 String (字符串) 命令
SET key value [EX seconds|PX milliseconds|NX|XX]
: 设置 key 的值。EX/PX
: 设置过期时间 (秒/毫秒)。NX
: 只在 key 不存在时设置。XX
: 只在 key 存在时设置。
GET key
: 获取 key 的值。GETSET key value
: 设置 key 的新值,并返回旧值。MSET key value [key value ...]
: 同时设置一个或多个 key-value 对。MGET key [key ...]
: 获取一个或多个 key 的值。INCR key
: 将 key 中储存的数字值增一 (key 不存在时,初始化为 0 再执行)。DECR key
: 将 key 中储存的数字值减一。INCRBY key increment
: 将 key 所储存的值加上指定的增量increment
。DECRBY key decrement
: 将 key 所储存的值减去指定的减量decrement
。APPEND key value
: 如果 key 已存在并且是字符串,将value
追加到 key 原有值的末尾。
三、 List (列表) 命令
LPUSH key element [element ...]
: 将一个或多个元素插入到列表头部。RPUSH key element [element ...]
: 将一个或多个元素插入到列表尾部。LPOP key [count]
: 移除并获取列表头部的count
个元素 (默认为 1)。RPOP key [count]
: 移除并获取列表尾部的count
个元素 (默认为 1)。LLEN key
: 获取列表的长度。LRANGE key start stop
: 获取列表指定范围内的元素 (下标start
到stop
)。LINDEX key index
: 通过索引获取列表中的元素。LSET key index element
: 通过索引设置列表元素的值。LTRIM key start stop
: 对一个列表进行修剪,只保留指定区间内的元素。
四、 Hash (哈希) 命令
HSET key field value [field value ...]
: 将哈希表 key 中的字段field
的值设为value
(可同时设置多个)。HGET key field
: 获取存储在哈希表中指定字段field
的值。HMSET key field value [field value ...]
: (已不推荐,请用 HSET) 同时将多个 field-value 对设置到哈希表 key 中。HMGET key field [field ...]
: 获取所有给定字段的值。HGETALL key
: 获取在哈希表中指定 key 的所有字段和值。HDEL key field [field ...]
: 删除一个或多个哈希表字段。HLEN key
: 获取哈希表中字段的数量。HEXISTS key field
: 查看哈希表 key 中,指定的字段field
是否存在。HKEYS key
: 获取哈希表中的所有字段。HVALS key
: 获取哈希表中的所有值。HINCRBY key field increment
: 为哈希表 key 中的指定字段field
的整数值加上增量increment
。
五、 Set (集合) 命令
SADD key member [member ...]
: 向集合添加一个或多个成员。SREM key member [member ...]
: 移除集合中一个或多个成员。SMEMBERS key
: 返回集合中的所有成员。SISMEMBER key member
: 判断member
元素是否是集合 key 的成员。SCARD key
: 获取集合的成员数。SPOP key [count]
: 随机移除并返回集合中count
个成员 (默认为 1)。SRANDMEMBER key [count]
: 随机返回集合中count
个成员,但不移除 (默认为 1)。SINTER key [key ...]
: 返回给定所有集合的交集。SUNION key [key ...]
: 返回给定所有集合的并集。SDIFF key [key ...]
: 返回给定所有集合的差集 (第一个集合与其他集合的差集)。
六、 Sorted Set (ZSet / 有序集合) 命令
ZADD key [NX|XX] [CH] [INCR] score member [score member ...]
: 向有序集合添加一个或多个成员,或者更新已存在成员的分数score
。ZREM key member [member ...]
: 移除有序集合中的一个或多个成员。ZCARD key
: 获取有序集合的成员数。ZCOUNT key min max
: 计算在有序集合中指定分数区间的成员数 (min
<= score <=max
)。ZSCORE key member
: 返回有序集合中,成员member
的分数score
。ZRANK key member
: 返回有序集合中指定成员的排名 (按分数从小到大)。ZREVRANK key member
: 返回有序集合中指定成员的排名 (按分数从大到小)。ZRANGE key start stop [WITHSCORES]
: 通过索引区间返回有序集合成中指定区间的成员 (从小到大)。ZREVRANGE key start stop [WITHSCORES]
: 通过索引区间返回有序集合成中指定区间的成员 (从大到小)。ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
: 通过分数区间返回有序集合指定区间的成员 (从小到大)。ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]
: 通过分数区间返回有序集合指定区间的成员 (从大到小)。ZINCRBY key increment member
: 为有序集合中指定成员member
的分数加上增量increment
。
1)set 命令用来存储一个键值对,在本例中,name 为 key,cmower 为 值。
2)get 命令用来获取一个键值对。
3)exists 命令用来测试一个键值对是否存在,(integer) 1
表示存在,(integer) 0
表示不存在。
4)del 命令用来删除一个键值对,(integer) 1
表示执行成功,(integer) 0
表示执行失败。
5)当键值对删除后,再通过 get 命令获取时,结果就为 (nil)
。
可能有小伙伴会好奇,nil
是什么意思?它是 Objective-C、Swift、Ruby、Lua 等编程语言中的一个关键字,
redis的Java客户端
spring data redis 在Java中操作redis数据
核心利器:RedisTemplate
与 StringRedisTemplate
Spring Data Redis 提供了 RedisTemplate<K, V>
作为核心操作类。它封装了对 Redis 的各种操作,并处理了连接管理和序列化。
为了方便处理最常见的字符串键值场景,Spring Data Redis 还提供了一个专门的子类:StringRedisTemplate
。它默认使用 StringRedisSerializer
来序列化 key 和 value,使得代码更简洁易读,尤其适合存储 JSON 字符串等场景。
在你的 Spring Bean (如 Service 或 Component) 中,可以直接注入它们:
Java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;@Service
public class RedisExampleService {@Autowiredprivate StringRedisTemplate stringRedisTemplate; // 推荐用于字符串操作// ... 操作方法
}
常用数据类型操作示例
StringRedisTemplate
提供了便捷的方法来操作 Redis 的五种基本数据类型:
-
**String (字符串)😗*Java
// 设置值 stringRedisTemplate.opsForValue().set("user:1:name", "Alice"); // 设置值并带过期时间 (10分钟) stringRedisTemplate.opsForValue().set("session:xyz", "user_token", 10, TimeUnit.MINUTES); // 获取值 String name = stringRedisTemplate.opsForValue().get("user:1:name"); // "Alice" // 删除值 stringRedisTemplate.delete("user:1:name");
-
**List (列表)😗*Java
// 从左侧推入元素 (模拟栈) stringRedisTemplate.opsForList().leftPush("tasks", "task1"); stringRedisTemplate.opsForList().leftPushAll("tasks", "task2", "task3"); // 获取列表长度 Long size = stringRedisTemplate.opsForList().size("tasks"); // 3 // 从右侧弹出一个元素 (模拟队列) String task = stringRedisTemplate.opsForList().rightPop("tasks"); // "task1"
-
**Hash (哈希)😗*Java
`// 设置哈希字段值 stringRedisTemplate.opsForHash().put("user:profile:1", "name", "Bob"); stringRedisTemplate.opsForHash().put("user:profile:1", "age", "30"); // 获取哈希字段值 Object age = stringRedisTemplate.opsForHash().get("user:profile:1", "age"); // "30" // 获取所有字段和值 Map<Object, Object> profile = stringRedisTemplate.opsForHash().entries("user:profile:1");`
-
**Set (集合)😗*Java
// 添加成员 stringRedisTemplate.opsForSet().add("tags:article:1", "java", "spring", "redis"); // 获取所有成员 Set<String> tags = stringRedisTemplate.opsForSet().members("tags:article:1"); // 判断成员是否存在 Boolean isMember = stringRedisTemplate.opsForSet().isMember("tags:article:1", "java"); // true
-
**Sorted Set (ZSet / 有序集合)😗*Java
// 添加成员及分数 (分数用于排序) stringRedisTemplate.opsForZSet().add("leaderboard", "player1", 100.0); stringRedisTemplate.opsForZSet().add("leaderboard", "player2", 85.5); // 按分数范围获取成员 (从小到大) Set<String> topPlayers = stringRedisTemplate.opsForZSet().range("leaderboard", 0, 2); // 获取排名前3的玩家 // 获取成员的分数 Double score = stringRedisTemplate.opsForZSet().score("leaderboard", "player1"); // 100.0
关于序列化
StringRedisTemplate
默认 key 和 value 都用字符串序列化。如果需要存储复杂的 Java 对象,可以使用 RedisTemplate<String, Object>
并配置合适的序列化器(如 Jackson2JsonRedisSerializer
将对象序列化为 JSON 字符串,或 JdkSerializationRedisSerializer
使用 Java 序列化)。但通常,将对象转为 JSON 字符串后用 StringRedisTemplate
存储是更常见且通用的做法。
总结
Spring Data Redis 通过 RedisTemplate
和 StringRedisTemplate
提供了一套简洁、强大的 API,让 Java 开发者可以非常方便地在 Spring 应用中集成和操作 Redis,专注于业务逻辑而非底层细节。它无疑是 Spring 技术栈中操作 Redis 的首选方案。
package com.sky.config;import lombok.extern.slf4j.Slf4j;
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;/*** 配置Redis连接和操作的相关设置*/
@Configuration
@Slf4j
public class RedisConfiguration {/*** 创建并配置RedisTemplate实例** @param redisConnectionFactory Redis连接工厂,用于创建Redis连接* @return RedisTemplate实例,用于操作Redis*/@Beanpublic RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){// 记录创建redisTemplate对象的日志log.info("开始创建redisTemplate对象");// 实例化RedisTemplateRedisTemplate redisTemplate = new RedisTemplate();// 设置Redis连接工厂redisTemplate.setConnectionFactory(redisConnectionFactory);// 设置键的序列化方式为StringRedisSerializer,以确保键的兼容性和正确读取redisTemplate.setKeySerializer(new StringRedisSerializer());// 返回配置好的RedisTemplate实例return redisTemplate;}
}
package com.sky.controller.admin;import com.sky.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;@RestController("admin")
@RequestMapping("/admin/shop")
@Slf4j
public class shopController {public static final String KEY = "SHOP_STATUS";@Autowiredprivate RedisTemplate redisTemplate;@PutMapping("/{status}")public Result setStatus(@PathVariable Integer status){log.info("设置店铺状态为{}",status==1?"营业中":"打烊中");redisTemplate.opsForValue().set(KEY,status);return Result.success();}@GetMapping("/status")public Result<Integer> getStatus(){Integer status = (Integer) redisTemplate.opsForValue().get(KEY);log.info("获取到店铺状态为{}",status==1?"营业中":"打烊中");return Result.success(status);}
}