Redis命令:APPEND

Redis APPEND 命令详细教程

APPEND 用于将给定值追加到指定 Key 现有字符串值的末尾。如果 Key 不存在,APPEND 会先以空字符串创建该 Key,再执行追加,效果等同于一次 SET。命令返回追加操作完成后字符串的总长度。它常用于原子地拼接文本片段、构建审计日志、累积遥测数据等场景。

本文基于 Redis String 数据类型介绍 APPEND。Redis 命令本身不区分大小写,因此 APPENDappendAppend 的效果相同;文档统一使用大写形式。APPEND 自 Redis 2.0.0 起可用。

资料合集:https://pan.quark.cn/s/10e98d308913https://pan.quark.cn/s/f56bc69c5338

一、命令概览

1. 基本语法

redis 复制代码
APPEND key value

参数说明:

参数 说明
key 目标 Key 名称
value 要追加到末尾的字符串内容,二进制安全,可包含任意字节

返回值:

  • 返回追加完成后字符串的总长度(整数)。
  • Key 不存在时,APPEND 创建 Key 并写入 value,返回 value 的长度。

2. 最简单的示例

对不存在的 Key 执行 APPEND,相当于创建它:

redis 复制代码
APPEND mykey "Hello"

返回:

text 复制代码
(integer) 5

继续追加内容:

redis 复制代码
APPEND mykey " World"

返回:

text 复制代码
(integer) 11

查看最终值:

redis 复制代码
GET mykey

返回:

text 复制代码
"Hello World"

3. 命令特性

  • APPEND 只作用于 String 类型的 Key,对其他类型返回 WRONGTYPE 错误。
  • 时间复杂度为 O(1),追加本身不复制整个已有字符串(SDS 动态字符串预分配策略摊薄了成本)。
  • APPEND 是原子命令:多个客户端并发追加同一 Key 时,Redis 按到达顺序串行执行,不会丢失任何一次追加。
  • APPEND 修改值但保留 Key 已有的过期时间,不会像不带选项的 SET 那样清除 TTL。
  • 单个 String 值的最大长度为 512 MB。

二、APPEND 的返回结果

1. Key 不存在:创建并返回新值长度

redis 复制代码
APPEND greeting "Hi"

返回:

text 复制代码
(integer) 2

Key 被创建,值为 "Hi"。此行为与 SET greeting "Hi" 的写入结果一致。

2. Key 存在:追加并返回总长度

redis 复制代码
SET greeting "Hello"
APPEND greeting " World"

返回:

text 复制代码
(integer) 11

值为 "Hello World",长度 11。返回值是追加后的总长度,不是本次追加部分的长度。

3. 追加空字符串

redis 复制代码
SET greeting "Hello"
APPEND greeting ""

返回:

text 复制代码
(integer) 5

追加空字符串不改变值和长度,命令正常执行并返回当前长度。

4. Key 存在但类型不是 String

redis 复制代码
RPUSH mylist a b c
APPEND mylist "d"

返回:

text 复制代码
(error) WRONGTYPE Operation against a key holding the wrong kind of value

APPEND 不支持 List 类型。需要向列表尾部添加元素应使用 RPUSH;两者还会产生完全不同的数据类型(String 与 List)。

5. 已过期的 Key

redis 复制代码
SET temp-key "old" EX 1

等待超过 1 秒后执行:

redis 复制代码
APPEND temp-key "new"

返回:

text 复制代码
(integer) 3

已过期的 Key 被视为不存在,APPEND"new" 重新创建 Key,长度为 3。新 Key 没有过期时间。

6. 二进制安全

APPEND 可以追加包含 \x00 等任意字节的二进制数据:

redis 复制代码
DEL bin-key
APPEND bin-key "a"
APPEND bin-key "\x00b"
STRLEN bin-key

STRLEN 返回 3,说明 \x00 作为普通字节存储,不截断字符串。

三、APPEND 与过期时间

APPEND 属于"修改现有值"的命令,它不会清除 Key 已有的 TTL:

redis 复制代码
SET log:job:1 "start" EX 100
TTL log:job:1
APPEND log:job:1 " - step1"
TTL log:job:1

追加后 TTL 继续递减(如返回 97),说明过期时间被保留。

这与不带过期选项的 SET 形成对比:

redis 复制代码
SET log:job:1 "overwrite"
TTL log:job:1

普通 SET 覆盖值后 TTL 被清除,TTL 返回 -1

需要注意:Key 不存在时 APPEND 创建的新 Key 永不过期,需要 TTL 时在创建后显式执行 EXPIRE,或改用 SET key value EX seconds

四、与相关命令的区别

1. APPEND 与 SET

SET 整体覆盖值,APPEND 在末尾追加:

redis 复制代码
SET msg "Hello"
SET msg "Hi"          # 值变为 "Hi",TTL 被清除
APPEND msg "!"        # 值变为 "Hi!"
对比项 SET APPEND
对现有值的影响 整体覆盖 末尾追加
Key 不存在时 创建 创建(等效写入 value)
对 TTL 的影响 不带选项时清除 保留
返回值 OK 追加后的总长度

2. APPEND 与 SETRANGE

SETRANGE 从指定偏移量开始覆盖写入,APPEND 只在末尾追加:

redis 复制代码
SET target "Hello World"
SETRANGE target 6 "Redis"   # 值变为 "Hello Redis"
APPEND target "!"           # 值变为 "Hello Redis!"

SETRANGE 的偏移量超过当前长度时会以 \x00 填充中间空隙,APPEND 不会产生填充字节。需要在中间或指定位置改写内容用 SETRANGE,纯尾部拼接用 APPEND

3. APPEND 与 GETRANGE / STRLEN

GETRANGE 读取字符串的指定区间,STRLEN 返回总长度。它们是 APPEND 的天然配套读命令:

redis 复制代码
APPEND events "a,b"
APPEND events ",c"
STRLEN events      # (integer) 4
GETRANGE events 0 -1   # "a,b,c"

APPEND 返回的长度也可直接替代一次 STRLEN 查询。

4. APPEND 与 RPUSH

两者都有"尾部添加"的语义,但数据类型不同:

对比项 APPEND RPUSH
数据类型 String List
Key 不存在时 创建 String 创建 List
返回值 追加后总长度 追加后列表长度
读取方式 GET / GETRANGE LRANGE / RPOP
适合场景 固定格式文本拼接、整体读取 无界增长、逐条消费

如果追加的内容将来需要逐条取出,应使用 RPUSH;只有整体读取时 String 拼接才有意义。

5. APPEND 与 INCR

INCR 对整数字符串做原子自增,APPEND 做字符串拼接,语义完全不同:

redis 复制代码
SET counter 1
INCR counter      # (integer) 2,数值语义
APPEND counter "0"  # (integer) 2,值变为 "20",字符串语义

"2" 执行 APPEND counter "0" 后值是字符串 "20" 而非数值加 10。计数场景使用 INCR/INCRBY,不要用 APPEND 拼接数字。

五、事务、Pipeline 与并发

1. 原子性

APPEND 是单条命令,服务端原子执行。多客户端并发对同一 Key 追加时,Redis 单线程按命令到达顺序串行处理,每次追加都不会丢失,这是 APPEND 相比"客户端 GET 拼接后 SET 回去"的核心优势:

text 复制代码
GET key -> 客户端拼接 -> SET key newvalue   # 非原子,并发下会互相覆盖
APPEND key value                            # 原子,无丢失

2. 在事务中使用

redis 复制代码
MULTI
APPEND log:1 "a"
APPEND log:1 "b"
STRLEN log:1
EXEC

EXEC 返回各命令结果:122

3. Pipeline 批量追加

需要拼接大量片段时,用 Pipeline 减少网络往返:

text 复制代码
APPEND buffer "part-1;"
APPEND buffer "part-2;"
APPEND buffer "part-3;"

Pipeline 中命令仍按顺序串行执行,追加顺序与发送顺序一致。

4. Lua 脚本中的条件拼接

需要"满足条件才追加"的原子逻辑时,使用 Lua 脚本:

redis 复制代码
EVAL "if redis.call('STRLEN', KEYS[1]) + #ARGV[1] <= tonumber(ARGV[2]) then return redis.call('APPEND', KEYS[1], ARGV[1]) else return -1 end" 1 buffer "chunk" 100

该脚本在追加后总长度不超过上限(100)时才执行追加,否则返回 -1,可用来限制字符串无限增长。

六、常见客户端用法

1. redis-cli

bash 复制代码
redis-cli APPEND mykey "Hello"
redis-cli APPEND mykey " World"
redis-cli STRLEN mykey
redis-cli GET mykey

两次 APPEND 分别返回 511STRLEN 返回 11

2. Python(redis-py)

python 复制代码
import redis

client = redis.Redis(host="localhost", port=6379, decode_responses=True)

print(client.append("mykey", "Hello"))    # 5
print(client.append("mykey", " World"))   # 11
print(client.get("mykey"))                # Hello World

3. Node.js(node-redis)

javascript 复制代码
import { createClient } from "redis";

const client = createClient();
await client.connect();

console.log(await client.append("mykey", "Hello"));   // 5
console.log(await client.append("mykey", " World"));  // 11
console.log(await client.get("mykey"));               // Hello World

await client.quit();

4. Java(Jedis)

java 复制代码
import redis.clients.jedis.Jedis;

try (Jedis jedis = new Jedis("localhost", 6379)) {
    System.out.println(jedis.append("mykey", "Hello"));    // 5
    System.out.println(jedis.append("mykey", " World"));   // 11
    System.out.println(jedis.get("mykey"));                // Hello World
}

各客户端的 append 方法均返回追加后的总长度(整数)。

七、典型业务场景

1. 审计与操作日志

把关键操作以定界符拼接到一个 Key 中,天然保持先后顺序:

redis 复制代码
APPEND audit:user:1001 "2026-09-10 login|"
APPEND audit:user:1001 "2026-09-10 change-password|"

读取时整体 GET 后按定界符拆分。日志量可能很大的场景应改用 List 或 Stream。

2. 递增构建大文本

分块生成报表、导出文件内容时逐块追加,避免客户端拼出超大字符串后再一次性 SET

text 复制代码
APPEND report:2026-09 "header;"
APPEND report:2026-09 "row-1;"
APPEND report:2026-09 "row-2;"

3. 遥测与轨迹片段累积

设备周期性上报位置片段,服务端原子累积:

redis 复制代码
APPEND track:device:7 "116.40,39.90;"

并发上报也不会丢失片段。

4. 一次性令牌或验证码的多次拼接

极少数需要分段生成的令牌(如先写前缀、再补随机段)可用 APPEND 完成,注意最终消费仍需配合 GETDEL 等命令。

5. 简单限定的消息缓冲

在单 Key 上聚合短消息,配合 TTL 定期失效,形成一个轻量的临时缓冲区:

redis 复制代码
APPEND buffer:5min "msg-1;"
EXPIRE buffer:5min 300

八、性能与使用建议

  1. 时间复杂度为 O(1):SDS 预分配机制使追加不需要每次整体复制,但注意总内存仍随追加增长。
  2. 单值上限 512 MBAPPEND 不会截断超限数据,超过上限会返回错误,务必在应用层限制追加总量。
  3. 警惕大 Key :无限追加会形成巨型 String,拖慢 GETDEL,复制和网络传输成本也高。无界增长的数据应改用 List、Stream 等结构。
  4. APPEND 保留 TTL,若期望"追加即永久",无需额外处理;若期望刷新 TTL,需显式 EXPIRE
  5. 高频追加同一 Key 时建议使用 Pipeline 批量发送,减少网络往返。
  6. 大 Key 清理使用 UNLINK 而非 DEL,避免阻塞主线程。
  7. APPEND 属于写命令(ACL 类别 @write@string@fast),会写入 AOF 并复制到从节点,高频追加会放大持久化与复制流量。
  8. 追加内容若将来要逐条消费,从设计阶段就选择 List/Stream,避免后期迁移大 Key。

九、常见问题排查

问题 1:返回的长度比预期大

检查历史追加是否残留旧内容:

redis 复制代码
STRLEN key
GETRANGE key 0 50

APPEND 不会清空已有值。需要全新内容时先 DEL/UNLINK,或直接用 SET 覆盖。

问题 2:报 WRONGTYPE 错误

redis 复制代码
TYPE key

目标 Key 是 List、Hash 等非 String 类型。确认业务应使用 RPUSH/HSET 等对应命令,还是先删除旧 Key 再用 APPEND 重建。

问题 3:追加后 Key 意外"永不过期"

Key 不存在时 APPEND 创建的新 Key 没有 TTL;存在时 APPEND 保留旧 TTL。若发现 Key 长期残留,排查是否曾被不带选项的 SET 覆盖或被 PERSIST,并重新设置 EXPIRE

问题 4:并发追加导致内容交错混乱

APPEND 本身不丢失数据,但多个客户端追加的多字节内容可能交错。每个客户端的片段应一次性完整追加,不要把一个逻辑片段拆成多次 APPEND

问题 5:Key 越来越大、读取变慢

STRLEN 监控增长,超过阈值(如 1 MB)时评估:

  • 改用 List/Stream 分片存储;
  • 定期读取后清理(GETDELUNLINK);
  • 在 Lua 脚本中加入长度上限拒绝追加(见第五章示例)。

问题 6:二进制内容显示异常

APPEND 二进制安全,客户端读取显示乱码通常是编码问题而非数据损坏。用 STRLEN 确认长度,按原始字节处理。

十、完整练习

下面的示例覆盖创建、追加、长度、空串、类型错误、TTL 保留、二进制安全与并发对比。请在测试数据库执行;FLUSHDB 会清空当前逻辑数据库中的全部 Key。

redis 复制代码
FLUSHDB

# 1. Key 不存在时创建
APPEND demo:greet "Hello"

# 2. 继续追加并观察总长度
APPEND demo:greet " World"
STRLEN demo:greet
GET demo:greet

# 3. 追加空字符串
APPEND demo:greet ""

# 4. 类型错误
RPUSH demo:list a b
APPEND demo:list "c"

# 5. TTL 保留
SET demo:log "start" EX 100
TTL demo:log
APPEND demo:log " - step1"
TTL demo:log
GET demo:log

# 6. SET 覆盖后 TTL 被清除(对比)
SET demo:log "overwrite"
TTL demo:log

# 7. 过期后 APPEND 重建
SET demo:temp "old" EX 1
# 等待 1 秒以上后执行:
# APPEND demo:temp "new"
# TTL demo:temp

# 8. 二进制安全
DEL demo:bin
APPEND demo:bin "a"
APPEND demo:bin "\x00b"
STRLEN demo:bin

# 9. 与 SETRANGE 对比
SET demo:text "Hello World"
SETRANGE demo:text 6 "Redis"
GET demo:text
APPEND demo:text "!"
GET demo:text

# 10. 与 INCR 对比(注意语义差异)
SET demo:num 1
INCR demo:num
GET demo:num
APPEND demo:num "0"
GET demo:num

# 11. Pipeline 模拟多次追加
APPEND demo:pipe "p1;"
APPEND demo:pipe "p2;"
APPEND demo:pipe "p3;"
GET demo:pipe

预期结果:

  • APPEND demo:greet "Hello" 返回 (integer) 5
  • APPEND demo:greet " World" 返回 (integer) 11STRLEN11,值为 "Hello World"
  • 追加空字符串返回 (integer) 11,长度不变。
  • 对 List 执行 APPEND 返回 (error) WRONGTYPE ...
  • 追加前 TTL demo:log100,追加后继续递减(如 97),值为 "start - step1"
  • SET 覆盖后 TTL demo:log 返回 -1
  • demo:temp 过期后 APPEND 重建,返回 (integer) 3TTL 返回 -1
  • demo:binSTRLEN 返回 3
  • SETRANGE 后值为 "Hello Redis",再 APPEND "!" 后为 "Hello Redis!"
  • INCR 后值为 "2"APPEND "0" 后值为 "20"
  • demo:pipe 的值为 "p1;p2;p3;"

十一、命令速查表

需求 命令
末尾追加内容 APPEND key value
整体覆盖写入 SET key value
指定偏移覆盖 SETRANGE key offset value
读取整个值 GET key
读取区间 GETRANGE key start end
查询长度 STRLEN key
列表尾部追加(List 类型) RPUSH key value [value ...]
数值自增 INCR key / INCRBY key n
读取并删除 GETDEL key
异步删除大 Key UNLINK key
设置过期时间 EXPIRE key seconds

总结

APPEND 的核心作用是将值原子地追加到 String Key 的末尾,Key 不存在时创建它,基本语法为:

redis 复制代码
APPEND key value

使用时重点注意五点:

  • 返回值是追加后的总长度;Key 不存在时等效 SET 创建。
  • 只作用于 String 类型,其他类型返回 WRONGTYPE;需要逐条消费的数据应使用 RPUSH(List)。
  • APPEND 是原子命令,并发追加不丢失数据,远优于"GET 后 SET 回写"的非原子流程。
  • 追加保留已有 TTL,但新建的 Key 永不过期;单值上限 512 MB,谨防大 Key。
  • SET/SETRANGE/INCR 的语义差异要分清:覆盖、定位改写、数值自增都不等同于尾部拼接。
相关推荐
敲代码的嘎仔1 小时前
从集群锁失效到异步领券:我用分布式锁 + Redisson + MQ 把领券接口 RT 从 200ms 压到 15ms
java·数据库·redis·分布式·缓存·ai·wpf
MetaLite4 小时前
Spring Cache只留注解-MetaLite如何二开缓存运行时
java·spring·缓存
wdfk_prog5 小时前
lely-canopen-rtt:为什么推荐在 RT-Thread 上使用 Lely CANopen 构建主站
java·运维·缓存·docker·容器
莫得感情 o6 小时前
Redis 12 · 缓存一致性:数据库与缓存双写怎么不乱
redis·缓存
吃饱了得干活8 小时前
Spring Boot + Redis 分布式锁:一个订单重复提交引发的六次迭代
java·redis·后端
李兆龙的博客8 小时前
问津集 #24:LiquidCache——面向过滤的缓存编码与计算下推
缓存
爱上网的小舟8 小时前
着色器缓存大小设置多少合适?N卡A卡缓存路径与清理方法
缓存·着色器
草莓熊Lotso9 小时前
【Redis 初阶】C++ 客户端实战:从 RESP 协议到 redis-plus-plus 工程化用法
linux·开发语言·网络·数据库·c++·redis·缓存
YHHLAI9 小时前
基于 Next.js 16 + Redis 的全栈笔记博客系统
javascript·redis·笔记