Redis 字符串
提示
来自deepseek解释
原文链接:https://redis.io/docs/latest/develop/data-types/strings/
代码示例图例
下面的代码示例展示了如何在不同编程语言和客户端库中执行相同的操作:
- Redis CLI:Redis 命令行界面
- C#(同步):StackExchange.Redis 同步客户端
- C#(异步):StackExchange.Redis 异步客户端
- Go:go-redis 客户端
- Java(同步 - Jedis):Jedis 同步客户端
- Java(异步 - Lettuce):Lettuce 异步客户端
- Java(响应式 - Lettuce):Lettuce 响应式/流式客户端
- JavaScript(Node.js):node-redis 客户端
- PHP:Predis 客户端
- Python:redis-py 客户端
- Rust(同步):redis-rs 同步客户端
- Rust(异步):redis-rs 异步客户端
每个代码示例都演示了不同语言中相同的基本操作。具体语法和模式因语言和客户端库而异,但底层的 Redis 命令和行为保持一致。
字符串命令摘要
本组共 26 条命令:
| 命令 | 摘要 | 复杂度 | 起始版本 |
|---|---|---|---|
| APPEND | 将字符串追加到键的值上。如果键不存在则创建它。 | O(1)。摊还时间复杂度为 O(1)... | 2.0.0 |
| DECR | 将键的整数值减一。如果键不存在则使用 0 作为初始值。 | O(1) | 1.0.0 |
| DECRBY | 从键的整数值中减去一个数值。如果键不存在则使用 0 作为初始值。 | O(1) | 1.0.0 |
| DELEX | 基于值或摘要比较,条件性地移除指定键。 | IFEQ/IFNE 为 O(1),IFDEQ/IFDNE 为 O(N)... | 8.4.0 |
| DIGEST | 返回字符串值的 XXH3 哈希。 | O(N),其中 N 是字符串值的长度。 | 8.4.0 |
| GET | 返回键的字符串值。 | O(1) | 1.0.0 |
| GETDEL | 删除键后返回其字符串值。 | O(1) | 6.2.0 |
| GETEX | 设置键的过期时间后返回其字符串值。 | O(1) | 6.2.0 |
| GETRANGE | 返回存储在键中的字符串的子串。 | O(N),其中 N 是返回字符串的长度... | 2.4.0 |
| GETSET | 将键设置为新值并返回之前的字符串值。 | O(1) | 1.0.0 |
字符串命令摘要(第 2 部分)
| 命令 | 摘要 | 复杂度 | 起始版本 |
|---|---|---|---|
| INCR | 将键的整数值加一。如果键不存在则使用 0 作为初始值。 | O(1) | 1.0.0 |
| INCRBY | 将键的整数值增加一个数值。如果键不存在则使用 0 作为初始值。 | O(1) | 1.0.0 |
| INCRBYFLOAT | 将键的浮点数值增加一个数值。如果键不存在则使用 0 作为初始值。 | O(1) | 2.6.0 |
| INCREX | 增加键的数值并设置其过期时间。如果键不存在则使用 0 作为初始值。 | O(1) | 8.8.0 |
| LCS | 查找最长公共子串。 | O(N*M),其中 N 和 M 分别是 s1 和 s2 的长度... | 7.0.0 |
| MGET | 原子性地返回一个或多个键的字符串值。 | O(N),其中 N 是要检索的键的数量。 | 1.0.0 |
| MSET | 原子性地创建或修改一个或多个键的字符串值。 | O(N),其中 N 是要设置的键的数量。 | 1.0.1 |
| MSETEX | 在单个操作中原子性地设置多个字符串键并共享过期时间。支持灵活的参数解析,条件和过期标志可以按任意顺序出现。 | O(N),其中 N 是要设置的键的数量。 | 8.4.0 |
| MSETNX | 仅当所有键都不存在时,原子性地修改一个或多个键的字符串值。 | O(N),其中 N 是要设置的键的数量。 | 1.0.1 |
| PSETEX | 以毫秒为单位设置键的字符串值和过期时间。如果键不存在则创建它。 | O(1) | 2.6.0 |
字符串命令摘要(第 3 部分)
| 命令 | 摘要 | 复杂度 | 起始版本 |
|---|---|---|---|
| SET | 设置键的字符串值,忽略其类型。如果键不存在则创建它。 | O(1) | 1.0.0 |
| SETEX | 设置键的字符串值和过期时间。如果键不存在则创建它。 | O(1) | 2.0.0 |
| SETNX | 仅当键不存在时设置键的字符串值。 | O(1) | 1.0.0 |
| SETRANGE | 从偏移量开始用另一个字符串覆盖字符串值的一部分。如果键不存在则创建它。 | O(1),不计算复制新字符串所需的时间... | 2.2.0 |
| STRLEN | 返回字符串值的长度。 | O(1) | 2.2.0 |
| SUBSTR | 返回字符串值的子串。 | O(N),其中 N 是返回字符串的长度... | 1.0.0 |
Redis 字符串存储字节序列,包括文本、序列化对象和二进制数组。因此,字符串是您可以与 Redis 键关联的最简单的值类型。它们通常用于缓存,但也支持额外功能,让您可以实现计数器并执行按位操作。
由于 Redis 键是字符串,当我们也将字符串类型用作值时,我们就是在将一个字符串映射到另一个字符串。字符串数据类型适用于多种用例,例如缓存 HTML 片段或页面。
基础:使用 SET 和 GET 设置和检索字符串值(覆盖已有值)
命令: SET, GET
复杂度:
- SET: O(1)
- GET: O(1)
可用客户端: Redis CLI, C#, Go, Java (异步 - Lettuce), Java (响应式 - Lettuce), Java (同步 - Jedis), JavaScript (Node.js), PHP, Python, Ruby, Rust (异步), Rust (同步)
Redis CLI
> SET bike:1 Deimos
OK
> GET bike:1
"Deimos"C#
var res1 = db.StringSet("bike:1", "Deimos");
Console.WriteLine(res1); // true
var res2 = db.StringGet("bike:1");
Console.WriteLine(res2); // DeimosGo
res1, err := rdb.Set(ctx, "bike:1", "Deimos", 0).Result()
if err != nil {
panic(err)
}
fmt.Println(res1) // >>> OK
res2, err := rdb.Get(ctx, "bike:1").Result()
if err != nil {
panic(err)
}
fmt.Println(res2) // >>> DeimosJava(异步 - Lettuce)
CompletableFuture<Void> setAndGet = asyncCommands.set("bike:1", "Deimos").thenCompose(v -> {
System.out.println(v); // >>> OK
return asyncCommands.get("bike:1");
})
.thenAccept(System.out::println) // >>> Deimos
.toCompletableFuture();Java(响应式 - Lettuce)
Mono<Void> setAndGet = reactiveCommands.set("bike:1", "Deimos").doOnNext(v -> {
System.out.println(v); // OK
}).flatMap(v -> reactiveCommands.get("bike:1")).doOnNext(res -> {
System.out.println(res); // Deimos
}).then();Java(同步 - Jedis)
String res1 = jedis.set("bike:1", "Deimos");
System.out.println(res1); // OK
String res2 = jedis.get("bike:1");
System.out.println(res2); // DeimosJavaScript(Node.js)
const res1 = await client.set("bike:1", "Deimos");
console.log(res1); // OK
const res2 = await client.get("bike:1");
console.log(res2); // DeimosPHP
$res1 = $r->set('bike:1', 'Deimos');
echo "$res1" . PHP_EOL;
// >>> OK
$res2 = $r->get('bike:1');
echo "$res2" . PHP_EOL;
// >>> DeimosPython
res1 = r.set("bike:1", "Deimos")
print(res1) # True
res2 = r.get("bike:1")
print(res2) # DeimosRuby
res1 = r.set('bike:1', 'Deimos')
puts res1 # OK
res2 = r.get('bike:1')
puts res2 # DeimosRust(异步)
if let Ok(res) = r.set("bike:1", "Deimos").await {
let res: String = res;
println!("{res}"); // >>> OK
}
match r.get("bike:1").await {
Ok(res) => {
let res: String = res;
println!("{res}"); // >>> Deimos
},
Err(e) => {
println!("Error getting foo: {e}");
return;
}
};Rust(同步)
if let Ok(res) = r.set("bike:1", "Deimos") {
let res: String = res;
println!("{res}"); // >>> OK
}
match r.get("bike:1") {
Ok(res) => {
let res: String = res;
println!("{res}"); // >>> Deimos
},
Err(e) => {
println!("Error getting bike:1: {e}");
return;
}
};如您所见,使用 SET 和 GET 命令是设置和检索字符串值的方式。注意,如果键已经存在,SET 将替换任何已存储在该键中的现有值,即使该键关联的是非字符串值也是如此。因此,SET 执行的是赋值操作。
值可以是各种类型的字符串(包括二进制数据),例如您可以在值中存储 jpeg 图片。值不能大于 512 MB。
SET 命令有一些有趣的选项,可以作为附加参数提供。例如,我可以要求 SET 在键已存在时失败,或相反,仅在键已存在时成功:
条件 SET 操作:当需要原子比较-设置行为时,使用 NX 和 XX 选项控制键的存在性
难度: 中级
构建基础: set_get
命令: SET
复杂度:
- SET: O(1)
可用客户端: Redis CLI, C#, Go, Java (异步 - Lettuce), Java (响应式 - Lettuce), Java (同步 - Jedis), JavaScript (Node.js), PHP, Python, Ruby, Rust (异步), Rust (同步)
Redis CLI
> SET bike:1 bike NX
(nil)
> SET bike:1 bike XX
OKC#
var res3 = db.StringSet("bike:1", "bike", when: When.NotExists);
Console.WriteLine(res3); // false
Console.WriteLine(db.StringGet("bike:1"));
var res4 = db.StringSet("bike:1", "bike", when: When.Exists);
Console.WriteLine(res4); // trueGo
res3, err := rdb.SetNX(ctx, "bike:1", "bike", 0).Result()
if err != nil {
panic(err)
}
fmt.Println(res3) // >>> false
res4, err := rdb.Get(ctx, "bike:1").Result()
if err != nil {
panic(err)
}
fmt.Println(res4) // >>> Deimos
res5, err := rdb.SetXX(ctx, "bike:1", "bike", 0).Result()
if err != nil {
panic(err)
}
fmt.Println(res5) // >>> OKJava(异步 - Lettuce)
CompletableFuture<Void> setnx = asyncCommands.setnx("bike:1", "bike").thenCompose(v -> {
System.out.println(v); // >>> false (因为键已存在)
return asyncCommands.get("bike:1");
})
.thenAccept(System.out::println) // >>> Deimos (值未改变)
.toCompletableFuture();
setnx.join();
// 如果键已存在,将值设置为 "bike"
CompletableFuture<Void> setxx = asyncCommands.set("bike:1", "bike", SetArgs.Builder.xx())
.thenAccept(System.out::println) // >>> OK
.toCompletableFuture();
setxx.join();Java(响应式 - Lettuce)
Mono<Void> setnx = reactiveCommands.setnx("bike:1", "bike").doOnNext(v -> {
System.out.println(v); // false (因为键已存在)
}).flatMap(v -> reactiveCommands.get("bike:1")).doOnNext(res -> {
System.out.println(res); // Deimos (值未改变)
}).then();
Mono<Void> setxx = reactiveCommands.set("bike:1", "bike", SetArgs.Builder.xx()).doOnNext(res -> {
System.out.println(res); // OK
}).then();Java(同步 - Jedis)
Long res3 = jedis.setnx("bike:1", "bike");
System.out.println(res3); // 0 (因为键已存在)
System.out.println(jedis.get("bike:1")); // Deimos (值未改变)
String res4 = jedis.set("bike:1", "bike", SetParams.setParams().xx()); // 如果键已存在,将值设置为 "bike"
System.out.println(res4); // OKJavaScript(Node.js)
const res3 = await client.set("bike:1", "bike", {'NX': true});
console.log(res3); // null
console.log(await client.get("bike:1")); // Deimos
const res4 = await client.set("bike:1", "bike", {'XX': true});
console.log(res4); // OKPHP
$res3 = $r->set('bike:1', 'bike', 'nx');
echo "$res3" . PHP_EOL;
// >>> (null)
echo $r->get('bike:1') . PHP_EOL;
// >>> Deimos
$res4 = $r->set('bike:1', 'bike', 'xx');
echo "$res4" . PHP_EOL;
// >>> OKPython
res3 = r.set("bike:1", "bike", nx=True)
print(res3) # None
print(r.get("bike:1")) # Deimos
res4 = r.set("bike:1", "bike", xx=True)
print(res4) # TrueRuby
res3 = r.set('bike:1', 'bike', nx: true)
puts res3 # false
puts r.get('bike:1') # Deimos
res4 = r.set('bike:1', 'bike', xx: true)
puts res4 # trueRust(异步)
if let Ok(res) = r.set_options("bike:1", "bike", redis::SetOptions::default().conditional_set(ExistenceCheck::NX)).await {
let res: bool = res;
println!("{res}"); // >>> false
}
match r.get("bike:1").await {
Ok(res) => {
let res: String = res;
println!("{res}"); // >>> Deimos
},
Err(e) => {
println!("Error getting foo: {e}");
return;
}
};
if let Ok(res) = r.set_options("bike:1", "bike", redis::SetOptions::default().conditional_set(ExistenceCheck::XX)).await {
let res: String = res;
println!("{res}"); // >>> OK
}
match r.get("bike:1").await {
Ok(res) => {
let res: String = res;
println!("{res}"); // >>> bike
},
Err(e) => {
println!("Error getting foo: {e}");
return;
}
};Rust(同步)
if let Ok(res) = r.set_options("bike:1", "bike", redis::SetOptions::default().conditional_set(ExistenceCheck::NX)) {
let res: bool = res;
println!("{res}"); // >>> false
}
match r.get("bike:1") {
Ok(res) => {
let res: String = res;
println!("{res}"); // >>> Deimos
},
Err(e) => {
println!("Error getting bike:1: {e}");
return;
}
};
if let Ok(res) = r.set_options("bike:1", "bike", redis::SetOptions::default().conditional_set(ExistenceCheck::XX)) {
let res: String = res;
println!("{res}"); // >>> OK
}
match r.get("bike:1") {
Ok(res) => {
let res: String = res;
println!("{res}"); // >>> bike
},
Err(e) => {
println!("Error getting bike:1: {e}");
return;
}
};还有大量其他用于操作字符串的命令。例如 GETSET 命令将键设置为新值,并返回旧值作为结果。例如,如果您有一个系统,每次网站收到新访问者时都会使用 INCR 递增一个 Redis 键,您可能希望每小时收集一次这些信息,而不丢失任何一次递增。您可以对键执行 GETSET,将其设置为新值 "0" 并读取旧值。
在单个命令中设置或检索多个键的值对于减少延迟也很有用。为此,提供了 MSET 和 MGET 命令:
使用 MSET 和 MGET 设置和检索多个值,减少与服务器的往返次数
构建基础: set_get
命令: MSET, MGET
复杂度:
- MSET: O(N)
- MGET: O(N)
可用客户端: Redis CLI, C#, Go, Java (异步 - Lettuce), Java (响应式 - Lettuce), Java (同步 - Jedis), JavaScript (Node.js), PHP, Python, Ruby, Rust (异步), Rust (同步)
Redis CLI
> MSET bike:1 "Deimos" bike:2 "Ares" bike:3 "Vanth"
OK
> MGET bike:1 bike:2 bike:3
1) "Deimos"
2) "Ares"
3) "Vanth"C#
var res5 = db.StringSet([
new ("bike:1", "Deimos"), new("bike:2", "Ares"), new("bike:3", "Vanth")
]);
Console.WriteLine(res5);
var res6 = db.StringGet(["bike:1", "bike:2", "bike:3"]);
Console.WriteLine(string.Join(", ", res6));Go
res6, err := rdb.MSet(ctx, "bike:1", "Deimos", "bike:2", "Ares", "bike:3", "Vanth").Result()
if err != nil {
panic(err)
}
fmt.Println(res6) // >>> OK
res7, err := rdb.MGet(ctx, "bike:1", "bike:2", "bike:3").Result()
if err != nil {
panic(err)
}
fmt.Println(res7) // >>> [Deimos Ares Vanth]Java(异步 - Lettuce)
Map<String, String> bikeMap = new HashMap<>();
bikeMap.put("bike:1", "Deimos");
bikeMap.put("bike:2", "Ares");
bikeMap.put("bike:3", "Vanth");
CompletableFuture<Void> mset = asyncCommands.mset(bikeMap).thenCompose(v -> {
System.out.println(v); // >>> OK
return asyncCommands.mget("bike:1", "bike:2", "bike:3");
})
.thenAccept(System.out::println)
// >>> [KeyValue[bike:1, Deimos], KeyValue[bike:2, Ares], KeyValue[bike:3,
// Vanth]]
.toCompletableFuture();Java(响应式 - Lettuce)
Map<String, String> bikeMap = new HashMap<>();
bikeMap.put("bike:1", "Deimos");
bikeMap.put("bike:2", "Ares");
bikeMap.put("bike:3", "Vanth");
Mono<Void> mset = reactiveCommands.mset(bikeMap).doOnNext(System.out::println) // OK
.flatMap(v -> reactiveCommands.mget("bike:1", "bike:2", "bike:3").collectList()).doOnNext(res -> {
System.out.println(res); // [KeyValue[bike:1, Deimos], KeyValue[bike:2, Ares], KeyValue[bike:3, Vanth]]
}).then();Java(同步 - Jedis)
String res5 = jedis.mset("bike:1", "Deimos", "bike:2", "Ares", "bike:3", "Vanth");
System.out.println(res5); // OK
List<String> res6 = jedis.mget("bike:1", "bike:2", "bike:3");
System.out.println(res6); // [Deimos, Ares, Vanth]JavaScript(Node.js)
const res5 = await client.mSet([
["bike:1", "Deimos"],
["bike:2", "Ares"],
["bike:3", "Vanth"]
]);
console.log(res5); // OK
const res6 = await client.mGet(["bike:1", "bike:2", "bike:3"]);
console.log(res6); // ['Deimos', 'Ares', 'Vanth']PHP
$res5 = $r->mset([
'bike:1' => 'Deimos', 'bike:2' => 'Ares', 'bike:3' => 'Vanth'
]);
echo "$res5" . PHP_EOL;
// >>> OK
$res6 = $r->mget(['bike:1', 'bike:2', 'bike:3']);
echo json_encode($res6) . PHP_EOL;
// >>> ["Deimos","Ares","Vanth"]Python
res5 = r.mset({"bike:1": "Deimos", "bike:2": "Ares", "bike:3": "Vanth"})
print(res5) # True
res6 = r.mget(["bike:1", "bike:2", "bike:3"])
print(res6) # ['Deimos', 'Ares', 'Vanth']Ruby
res5 = r.mset('bike:1', 'Deimos', 'bike:2', 'Ares', 'bike:3', 'Vanth')
puts res5 # OK
res6 = r.mget('bike:1', 'bike:2', 'bike:3')
puts res6.inspect # ["Deimos", "Ares", "Vanth"]Rust(异步)
if let Ok(res) = r.mset(&[("bike:1", "Deimos"), ("bike:2", "Ares"), ("bike:3", "Vanth")]).await {
let res: String = res;
println!("{res}"); // >>> OK
}
match r.mget(&["bike:1", "bike:2", "bike:3"]).await {
Ok(res) => {
let res: Vec<String> = res;
println!("{res:?}"); // >>> ["Deimos", "Ares", "Vanth"]
},
Err(e) => {
println!("Error getting foo: {e}");
return;
}
};Rust(同步)
if let Ok(res) = r.mset(&[("bike:1", "Deimos"), ("bike:2", "Ares"), ("bike:3", "Vanth")]) {
let res: String = res;
println!("{res}"); // >>> OK
}
match r.mget(&["bike:1", "bike:2", "bike:3"]) {
Ok(res) => {
let res: Vec<String> = res;
println!("{res:?}"); // >>> ["Deimos", "Ares", "Vanth"]
},
Err(e) => {
println!("Error getting values: {e}");
return;
}
};使用 MGET 时,Redis 返回一个值数组。
字符串作为计数器
即使字符串是 Redis 的基本值,您也可以对它们执行一些有趣的操作。例如,一个是原子递增:
原子计数器:当需要线程安全操作时,使用 INCR 和 INCRBY 递增字符串值(如果键不存在则初始化为 0)
构建基础: set_get
命令: SET, INCR, INCRBY
复杂度:
- SET: O(1)
- INCR: O(1)
- INCRBY: O(1)
可用客户端: Redis CLI, C#, Go, Java (异步 - Lettuce), Java (响应式 - Lettuce), Java (同步 - Jedis), JavaScript (Node.js), PHP, Python, Ruby, Rust (异步), Rust (同步)
Redis CLI
> SET total_crashes 0
OK
> INCR total_crashes
(integer) 1
> INCRBY total_crashes 10
(integer) 11C#
db.StringSet("total_crashes", 0);
var res7 = db.StringIncrement("total_crashes");
Console.WriteLine(res7); // 1
var res8 = db.StringIncrement("total_crashes", 10);
Console.WriteLine(res8);Go
res8, err := rdb.Set(ctx, "total_crashes", "0", 0).Result()
if err != nil {
panic(err)
}
fmt.Println(res8) // >>> OK
res9, err := rdb.Incr(ctx, "total_crashes").Result()
if err != nil {
panic(err)
}
fmt.Println(res9) // >>> 1
res10, err := rdb.IncrBy(ctx, "total_crashes", 10).Result()
if err != nil {
panic(err)
}
fmt.Println(res10) // >>> 11Java(异步 - Lettuce)
CompletableFuture<Void> incrby = asyncCommands.set("total_crashes", "0")
.thenCompose(v -> asyncCommands.incr("total_crashes")).thenCompose(v -> {
System.out.println(v); // >>> 1
return asyncCommands.incrby("total_crashes", 10);
})
.thenAccept(System.out::println) // >>> 11
.toCompletableFuture();Java(响应式 - Lettuce)
Mono<Void> incrby = reactiveCommands.set("total_crashes", "0").flatMap(v -> reactiveCommands.incr("total_crashes"))
.doOnNext(v -> {
System.out.println(v); // 1
}).flatMap(v -> reactiveCommands.incrby("total_crashes", 10)).doOnNext(res -> {
System.out.println(res); // 11
}).then();Java(同步 - Jedis)
jedis.set("total_crashes", "0");
Long res7 = jedis.incr("total_crashes");
System.out.println(res7); // 1
Long res8 = jedis.incrBy("total_crashes", 10);
System.out.println(res8); // 11JavaScript(Node.js)
await client.set("total_crashes", 0);
const res7 = await client.incr("total_crashes");
console.log(res7); // 1
const res8 = await client.incrBy("total_crashes", 10);
console.log(res8); // 11PHP
$r->set('total_crashes', 0);
$res7 = $r->incr('total_crashes');
echo "$res7" . PHP_EOL;
// >>> 1
$res8 = $r->incrby('total_crashes', 10);
echo "$res8" . PHP_EOL;
// >>> 11Python
r.set("total_crashes", 0)
res7 = r.incr("total_crashes")
print(res7) # 1
res8 = r.incrby("total_crashes", 10)
print(res8) # 11Ruby
r.set('total_crashes', 0)
res7 = r.incr('total_crashes')
puts res7 # 1
res8 = r.incrby('total_crashes', 10)
puts res8 # 11Rust(异步)
if let Ok(res) = r.set("total_crashes", 0).await {
let res: String = res;
println!("{res}"); // >>> OK
}
if let Ok(res) = r.incr("total_crashes", 1).await {
let res: i32 = res;
println!("{res}"); // >>> 1
}
if let Ok(res) = r.incr("total_crashes", 10).await {
let res: i32 = res;
println!("{res}"); // >>> 11
}Rust(同步)
if let Ok(res) = r.set("total_crashes", 0) {
let res: String = res;
println!("{res}"); // >>> OK
}
if let Ok(res) = r.incr("total_crashes", 1) {
let res: i32 = res;
println!("{res}"); // >>> 1
}
if let Ok(res) = r.incr("total_crashes", 10) {
let res: i32 = res;
println!("{res}"); // >>> 11
}INCR 命令将字符串值解析为整数,将其加一,最后将获得的值设置为新值。还有其他类似的命令,如 INCRBY、DECR 和 DECRBY。在内部它们总是相同的命令,只是行为略有不同。
INCR 是原子的意味着什么?这意味着即使多个客户端对同一个键执行 INCR,也永远不会出现竞争条件。例如,永远不会发生客户端 1 读取 "10",客户端 2 同时读取 "10",两者都递增到 11,然后将新值设置为 11。最终值始终是 12,并且读取-递增-设置操作是在所有其他客户端不同时执行命令的情况下执行的。
限制
默认情况下,单个 Redis 字符串最大为 512 MB。
按位操作和位域操作
要对字符串执行按位操作,请参阅位图数据类型文档。要在字符串中存储和操作整数值,请参阅位域数据类型文档。
性能
大多数字符串操作都是 O(1) 的,这意味着它们非常高效。但要注意 SUBSTR、GETRANGE 和 SETRANGE 命令,它们可能是 O(n)。这些随机访问字符串命令在处理大字符串时可能会导致性能问题。
替代方案
如果您将结构化数据存储为序列化字符串,您也可以考虑 Redis 哈希 或 JSON。
了解更多
- Redis Strings Explained 是一个关于 Redis 字符串的简短、全面的视频讲解。
- Redis University 的 RU101 详细介绍了 Redis 字符串。