📦 Redis 資料型態:String、List、Hash、Set、Sorted Set
📌 五大資料型態總覽
Redis 不只是簡單的 Key-Value 存儲,它支援 五種核心資料型態:
| 型態 |
說明 |
常見用途 |
| String |
字串(最基本) |
快取、計數器、Session |
| List |
有序列表 |
訊息佇列、最新動態 |
| Hash |
雜湊表(欄位-值) |
物件儲存、使用者資料 |
| Set |
無序集合(不重複) |
標籤、共同好友 |
| Sorted Set |
有序集合(帶分數) |
排行榜、延遲佇列 |
📌 String:最基本的鍵值對
# 基本操作
SET name "DevLearn"
GET name # "DevLearn"
# 設定過期時間(秒)
SET token "abc123" EX 3600
# 數值操作
SET counter 0
INCR counter # 1
INCR counter # 2
DECR counter # 1
INCRBY counter 10 # 11
# 批量操作
MSET key1 "val1" key2 "val2"
MGET key1 key2
.NET 程式碼範例
using StackExchange.Redis;
var redis = ConnectionMultiplexer.Connect("localhost:6379");
var db = redis.GetDatabase();
// 字串操作
await db.StringSetAsync("name", "DevLearn");
string name = await db.StringGetAsync("name");
// 帶過期時間
await db.StringSetAsync("token", "abc123", TimeSpan.FromHours(1));
// 計數器
await db.StringSetAsync("views", 0);
long newViews = await db.StringIncrementAsync("views"); // 1
long decreased = await db.StringDecrementAsync("views"); // 0
long addTen = await db.StringIncrementAsync("views", 10); // 10
📌 List:有序列表
# 從左邊推入
LPUSH tasks "task3" "task2" "task1"
# 從右邊推入
RPUSH tasks "task4"
# 取得範圍(0-based,-1 代表最後一個)
LRANGE tasks 0 -1
# 1) "task1" 2) "task2" 3) "task3" 4) "task4"
# 從左邊彈出
LPOP tasks # "task1"
# 列表長度
LLEN tasks # 3
.NET 程式碼範例
// List 操作
await db.ListLeftPushAsync("notifications", "新訂單 #1001");
await db.ListLeftPushAsync("notifications", "新訂單 #1002");
// 取得最新 10 筆通知
RedisValue[] recent = await db.ListRangeAsync("notifications", 0, 9);
foreach (var item in recent)
Console.WriteLine(item); // 新訂單 #1002, 新訂單 #1001
// 彈出(當作佇列使用)
string next = await db.ListRightPopAsync("notifications");
📌 Hash:雜湊表(最適合存物件)
# 設定多個欄位
HSET user:1001 name "Mike" email "mike@test.com" age "30"
# 取得單一欄位
HGET user:1001 name # "Mike"
# 取得所有欄位
HGETALL user:1001
# 1) "name" 2) "Mike"
# 3) "email" 4) "mike@test.com"
# 5) "age" 6) "30"
# 增加數值欄位
HINCRBY user:1001 age 1 # 31
.NET 程式碼範例
// Hash 操作:儲存使用者資料
var userKey = "user:1001";
await db.HashSetAsync(userKey, new HashEntry[]
{
new("name", "Mike"),
new("email", "mike@test.com"),
new("age", 30)
});
// 取得單一欄位
string userName = await db.HashGetAsync(userKey, "name");
// 取得所有欄位
HashEntry[] allFields = await db.HashGetAllAsync(userKey);
foreach (var field in allFields)
Console.WriteLine($"{field.Name}: {field.Value}");
// 數值遞增
await db.HashIncrementAsync(userKey, "age", 1);
📌 Set:無序集合(不重複)
# 新增成員
SADD tags:post:1 "csharp" "dotnet" "redis"
SADD tags:post:2 "csharp" "docker" "redis"
# 列出所有成員
SMEMBERS tags:post:1
# 1) "csharp" 2) "dotnet" 3) "redis"
# 交集(兩篇文章共同的標籤)
SINTER tags:post:1 tags:post:2
# 1) "csharp" 2) "redis"
# 聯集
SUNION tags:post:1 tags:post:2
# 是否為成員
SISMEMBER tags:post:1 "docker" # 0 (false)
.NET 程式碼範例
// Set 操作
await db.SetAddAsync("online:users", "user:1001");
await db.SetAddAsync("online:users", "user:1002");
await db.SetAddAsync("online:users", "user:1001"); // 重複不會加入
// 取得所有線上用戶
RedisValue[] onlineUsers = await db.SetMembersAsync("online:users");
// 檢查是否在線
bool isOnline = await db.SetContainsAsync("online:users", "user:1001");
// 交集:共同好友
await db.SetAddAsync("friends:mike", new RedisValue[] { "alice", "bob", "charlie" });
await db.SetAddAsync("friends:jane", new RedisValue[] { "bob", "charlie", "dave" });
RedisValue[] mutual = await db.SetCombineAsync(SetOperation.Intersect,
"friends:mike", "friends:jane");
// ["bob", "charlie"]
📌 Sorted Set:有序集合(排行榜神器)
# 新增成員(帶分數)
ZADD leaderboard 1500 "player:mike"
ZADD leaderboard 2000 "player:jane"
ZADD leaderboard 1800 "player:bob"
# 排名(由高到低)
ZREVRANGE leaderboard 0 -1 WITHSCORES
# 1) "player:jane" 2) "2000"
# 3) "player:bob" 4) "1800"
# 5) "player:mike" 6) "1500"
# 查排名(0-based)
ZREVRANK leaderboard "player:mike" # 2
# 增加分數
ZINCRBY leaderboard 600 "player:mike" # 2100
.NET 程式碼範例
// Sorted Set:排行榜
await db.SortedSetAddAsync("leaderboard", "player:mike", 1500);
await db.SortedSetAddAsync("leaderboard", "player:jane", 2000);
await db.SortedSetAddAsync("leaderboard", "player:bob", 1800);
// 取得 Top 10(分數由高到低)
var top10 = await db.SortedSetRangeByRankWithScoresAsync(
"leaderboard", 0, 9, Order.Descending);
foreach (var entry in top10)
Console.WriteLine($"{entry.Element}: {entry.Score}");
// 查排名
long? rank = await db.SortedSetRankAsync(
"leaderboard", "player:mike", Order.Descending);
// 增加分數
await db.SortedSetIncrementAsync("leaderboard", "player:mike", 600);
📌 如何選擇正確的資料型態?
需要儲存簡單值或計數? → String
需要先進先出的佇列? → List
需要儲存物件的多個欄位? → Hash
需要不重複的集合運算? → Set
需要排序或排行榜? → Sorted Set
| 需求 |
推薦型態 |
範例 |
| API 回應快取 |
String |
整個 JSON 字串 |
| 使用者 Profile |
Hash |
name, email, age 各欄位 |
| 最新 100 筆通知 |
List |
LPUSH + LTRIM |
| 線上用戶列表 |
Set |
自動去重 |
| 遊戲排行榜 |
Sorted Set |
分數排序 |
🔑 重點整理
- String 是最基本的型態,支援 INCR/DECR 做計數器
- List 適合佇列場景,LPUSH + RPOP 就是一個簡單的 MQ
- Hash 最適合存物件,每個欄位獨立操作
- Set 用於集合運算,如交集找共同好友
- Sorted Set 是排行榜的最佳解,自動依分數排序