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
5种数据类型(value)
Redis 作为一款高性能的内存键值数据库,其丰富的数据结构是支撑其广泛应用场景的关键。对于 Java 开发者而言,理解 Redis 的核心数据类型是高效使用 Redis 的第一步。幸运的是,Redis 的许多数据结构在概念上与 Java 集合框架(Java Collection Framework, JCF)中的容器有相似之处。本文旨在通过与 JCF 的类比,帮助 Java 开发者更直观、深入地理解 Redis 的五种基本数据类型:String、List、Hash、Set 和 Sorted Set (ZSet)。
注意: 类比有助于理解,但务必认识到 Redis 与 Java 在运行环境(网络、内存管理、持久化)和操作特性(原子性、服务器端计算)上的本质区别。
String
/ 基本类型包装类INCR
, DECR
),可以进行位操作(GETBIT
, SETBIT
)。java.lang.String
或基本数据类型的包装类 (Integer
, Long
, Double
, etc.)
INCR
/DECR
等命令是原子性的,由 Redis 服务器保证,这对于分布式计数器等场景非常关键。Java 中对包装类的 i++
操作在并发环境下并非原子操作,需要 AtomicInteger
等原子类。String
是 UTF-16 编码的字符序列,基本类型有明确的数值类型。String
是不可变的,而 Redis String 可以通过 APPEND
, SETRANGE
等命令进行修改。java.util.LinkedList
(Deque
/List
)LPUSH
, RPUSH
)和弹出(LPOP
, RPOP
)操作。LRANGE
,但非两端操作复杂度较高)。java.util.LinkedList
LinkedList
同时实现了 List
和 Deque
接口,其双向链表的底层实现使得在头尾添加/删除元素非常高效(O(1)),这与 Redis List 的核心特性高度吻合。可以模拟队列(FIFO,RPUSH
/LPOP
)或栈(LIFO,LPUSH
/LPOP
)。BLPOP
, BRPOP
),可以用于实现可靠的消息队列,Java 标准库的 LinkedList
本身不直接提供阻塞功能(需要 BlockingQueue
实现类)。LinkedList
的每个节点都有额外的指针开销。LinkedList
可以存储任意对象引用。java.util.HashMap
HGET
, HSET
),比序列化整个对象存入 String 更高效、灵活。java.util.HashMap
(简化) 或 java.util.HashMap
(概念)
HashMap
的 key,Redis Hash 的 value 相当于 HashMap
的 value。HashMap
的 key 和 value 可以是任意 Java 对象。HINCRBY
是原子性的。HashMap
操作需要外部同步机制保证并发安全。java.util.HashSet
SISMEMBER
),并提供强大的服务器端集合运算能力(交集 SINTER
, 并集 SUNION
, 差集 SDIFF
)。java.util.HashSet
HashSet
的迭代顺序可能受插入顺序和哈希冲突影响,但不保证稳定)。SRANDMEMBER
(随机获取一个或多个元素)和 SPOP
(随机移除并返回一个或多个元素)命令。java.util.TreeMap
/ java.util.TreeSet
(结合 Score)ZRANGEBYSCORE
) 或排名范围 (ZRANGE
) 高效查找,支持获取元素排名 (ZRANK
) 和分数 (ZSCORE
)。TreeMap>
或 TreeSet
(其中 Element 根据 score 实现 Comparable) 或 java.util.NavigableMap
/NavigableSet
TreeSet
基于元素的自然顺序或 Comparator
排序,TreeMap
基于 key 的顺序。可以模拟 ZSet 的 score 排序特性。TreeMap>
模拟时,如果多个 member 具有相同的 score,需要一个 Set 来存储。用 TreeSet
模拟时,需要设计一个包含 member 和 score 的 Element
类,并实现其比较逻辑。ZRANK
)、范围查询 (ZRANGE
, ZRANGEBYSCORE
) 等操作有专门优化(通常是 O(log N) 或 O(log N + M) 复杂度)。Java 中虽然 TreeMap
/TreeSet
也能实现范围查询,但获取排名等操作可能不那么直接或高效。double
类型。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
当中。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 原有值的末尾。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
: 对一个列表进行修剪,只保留指定区间内的元素。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
。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 ...]
: 返回给定所有集合的差集 (第一个集合与其他集合的差集)。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 等编程语言中的一个关键字,
spring data redis 在Java中操作redis数据
RedisTemplate
与 StringRedisTemplate
Spring Data Redis 提供了 RedisTemplate
作为核心操作类。它封装了对 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 {
@Autowired
private 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
并配置合适的序列化器(如 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
*/
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){
// 记录创建redisTemplate对象的日志
log.info("开始创建redisTemplate对象");
// 实例化RedisTemplate
RedisTemplate 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";
@Autowired
private 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);
}
}