Redis 字符串(下)

本课学习字符串的数值操作和位操作,这些功能让字符串可以用于计数器、统计等场景。

数值操作

Redis字符串可以存储整数,并支持原子性的数值操作。

INCR和DECR:自增和自减

REDIS
# 设置初始值
SET counter 10

# 自增1
INCR counter
(integer) 11

# 自减1
DECR counter
(integer) 10
💡 原子性: INCR和DECR是原子操作,多个客户端同时INCR不会冲突,适合实现计数器。

INCRBY和DECRBY:指定增量

REDIS
SET counter 100

# 增加10
INCRBY counter 10
(integer) 110

# 减少20
DECRBY counter 20
(integer) 90

INCRBYFLOAT:浮点数操作

REDIS
SET price 10.5

# 增加2.3
INCRBYFLOAT price 2.3
"12.8"

# 减小1.5(传负数)
INCRBYFLOAT price -1.5
"11.3"
⚠️ 注意: INCRBYFLOAT返回字符串格式的浮点数,不是整数。

数值操作的限制

REDIS
# 对非数字字符串操作会报错
SET text "hello"
INCR text
(error) ERR value is not an integer or out of range

# 对不存在的键操作(初始为0)
INCR newcounter
(integer) 1  # 从0增加到1

应用场景:计数器

REDIS
# 文章阅读数
INCR article:123:views
(integer) 1

# 用户点赞数
INCR user:456:likes
(integer) 1

# API调用次数
INCR api:usage:20260623
(integer) 1

范围操作

GETRANGE:获取子串

REDIS
SET message "Hello Redis World"

# 获取前5个字符
GETRANGE message 0 4
"Hello"

# 获取中间部分
GETRANGE message 6 10
"Redis"

# 获取最后5个字符
GETRANGE message -5 -1
"World"

# 获取全部
GETRANGE message 0 -1
"Hello Redis World"
💡 索引规则:

  • 索引从0开始
  • 包含结束位置
  • 负数表示从末尾计数(-1是最后一个字符)

SETRANGE:替换子串

REDIS
SET message "Hello World"

# 从位置6开始替换
SETRANGE message 6 "Redis"
(integer) 11  # 返回字符串长度

GET message
"Hello Redis"

# 替换超出原长度(自动填充)
SET short "Hi"
SETRANGE short 5 "There"
(integer) 10

GET short
"Hi\x00\x00\x00There"  # 中间用空字节填充
⚠️ 注意: SETRANGE如果超出原字符串长度,中间会用空字节(\x00)填充。

位操作

Redis字符串支持位操作,可以用于实现布隆过滤器、位图统计等。

SETBIT和GETBIT:设置和获取位

REDIS
# 设置位图(初始为0)
SETBIT mybitmap 0 1
(integer) 0  # 返回旧值

SETBIT mybitmap 2 1
(integer) 0

SETBIT mybitmap 7 1
(integer) 0

# 获取位的值
GETBIT mybitmap 0
(integer) 1

GETBIT mybitmap 1
(integer) 0

GETBIT mybitmap 2
(integer) 1

BITCOUNT:统计位为1的数量

REDIS
# 统计所有位
BITCOUNT mybitmap
(integer) 3  # 有3个位为1

# 统计指定字节范围
BITCOUNT mybitmap 0 0
(integer) 3  # 第0个字节有3个位为1

BITOP:位运算

REDIS
# 创建两个位图
SETBIT bitmap1 0 1
SETBIT bitmap1 1 1
SETBIT bitmap2 1 1
SETBIT bitmap2 2 1

# AND(与运算)
BITOP AND result bitmap1 bitmap2
(integer) 1

GETBIT result 1
(integer) 1  # 只有第1位都为1

# OR(或运算)
BITOP OR result bitmap1 bitmap2
(integer) 1

# XOR(异或运算)
BITOP XOR result bitmap1 bitmap2
(integer) 1

# NOT(非运算,仅支持一个键)
BITOP NOT result bitmap1
(integer) 1

BITPOS:查找第一个0或1的位置

REDIS
SET mykey "\xff\xf0\x00"  # 二进制:11111111 11110000 00000000

# 查找第一个0的位置
BITPOS mykey 0
(integer) 12  # 第12位是第一个0

# 查找第一个1的位置
BITPOS mykey 1
(integer) 0  # 第0位是第一个1

# 在指定字节范围内查找
BITPOS mykey 1 1 2
(integer) 8  # 在第1-2字节范围内,第8位是第一个1

应用场景:用户签到

REDIS
# 用户ID为123,2026年6月23日签到(第174天)
SETBIT user:123:signin:2026 174 1

# 检查是否签到
GETBIT user:123:signin:2026 174
(integer) 1

# 统计全年签到次数
BITCOUNT user:123:signin:2026
(integer) 50  # 签到了50天

# 检查连续签到(需要结合BITPOS和业务逻辑)

应用场景:在线用户统计

REDIS
# 用户123上线
SETBIT online:users 123 1

# 用户456上线
SETBIT online:users 456 1

# 统计在线人数
BITCOUNT online:users
(integer) 2

# 用户123下线
SETBIT online:users 123 0

字符串实用技巧

1. 生成唯一ID

REDIS
# 使用INCR生成自增ID
SET next:user:id 1000

INCR next:user:id
(integer) 1001  # 新用户ID

INCR next:user:id
(integer) 1002

2. 限流计数器

REDIS
# API限流:每分钟最多100次
SET limit:api:user:1 0 EX 60

INCR limit:api:user:1
(integer) 1

# 检查是否超限
GET limit:api:user:1
"50"  # 当前已调用50次

3. 分布式序列号

REDIS
# 订单号生成
SET order:sequence 1000000000

INCR order:sequence
(integer) 1000000001  # 新订单号

4. 统计UV(独立访客)

REDIS
# 使用位图统计UV
SETBIT uv:20260623 12345 1  # 用户ID 12345 访问
SETBIT uv:20260623 67890 1  # 用户ID 67890 访问

# 统计UV
BITCOUNT uv:20260623
(integer) 2  # 2个独立访客

性能优化建议

1. 使用批量操作

REDIS
# ❌ 多次单独操作
SET key1 "value1"
SET key2 "value2"
SET key3 "value3"

# ✅ 批量操作
MSET key1 "value1" key2 "value2" key3 "value3"

2. 合理设置过期时间

REDIS
# 缓存数据设置过期时间
SET cache:key "value" EX 3600

# 避免缓存雪崩:过期时间加随机值
SET cache:key "value" EX 3600

3. 选择合适的编码

REDIS
# 短字符串使用embstr编码(≤44字节)
SET short "Hello Redis"

# 长字符串使用raw编码
SET long "This is a very long string..."

# 查看编码
OBJECT ENCODING short
"embstr"

❓ 常见问题

Q INCR操作会溢出吗?
A 会。Redis整数范围是64位有符号整数(-2^63到2^63-1)。超出范围会报错。
Q 如何实现浮点数计数器?
A 使用INCRBYFLOAT命令,但注意它返回字符串格式。
Q 位操作有什么实际用途?
A 位图可用于用户签到、在线用户统计、布隆过滤器、权限位等场景,非常节省内存。
Q GETRANGE的时间复杂度是多少?
A O(N),N是返回子串的长度。获取很短的子串很快。
Q 如何存储大文本(如文章内容)?
A 建议压缩后存储,或分片存储。但更好的方案是存储在文件系统或对象存储中,Redis只存URL。

📖 小节

📝 作业

  1. 计数器: 实现一个文章阅读计数器,模拟10次阅读,查看最终计数
  2. 范围操作: 设置一个长字符串,使用GETRANGE获取不同部分
  3. 位图签到: 使用位图实现用户签到功能,统计签到天数
  4. UV统计: 使用位图统计网站UV,模拟多个用户访问

下一课

下一课我们将学习 Redis 哈希(上),学习哈希的基本操作。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏