SETBIT

设置或清除字符串值偏移处的位。如果键不存在,则创建该键。

语法

SETBIT key offset value

引入版本:2.2.0

复杂度摘要:O(1)

设置或清除 关键 中存储的字符串值中 偏移量 的位。

该位的设置或清除取决于 价值,它可以是 0 或 1。

当关键不存在时,创建一个新的字符串值。该字符串会不断增长,以确保它可以在 偏移量 处容纳一个位。 偏移量 参数必须大于或等于 0,且小于 2^32(这将位图限制为 512MB)。当 关键 处的字符串增长时,添加的位将设置为 0。

[!警告] 当设置最后一个可能位(偏移量 等于 2^32 -1)并且 关键 中存储的字符串值尚未保存字符串值或保存的字符串值较小时,Redis 需要分配所有中间内存,这可能会阻塞服务器一段时间。

请注意,一旦完成第一次分配,后续对同一 关键 调用 SETBIT 将不会产生分配开销。

必需参数

key

保存字符串的键的名称。

offset

要设置的从零开始的位偏移量。如果偏移量超出其当前长度,则字符串将以零填充。

value

要设置的位值:0 或 1。

示例

redis> SETBIT mykey 7 1
(integer) 0
redis> SETBIT mykey 7 0
(integer) 1
redis> GET mykey
"\x00"

详细说明

模式:访问整个位图

在某些情况下,您需要一次设置单个位图的所有位,例如将其初始化为默认的非零值时。可以通过多次调用 SETBIT 命令来完成此操作,每个命令对应一个需要设置的位。但是,作为优化,您可以使用单个 SET 命令来设置整个位图。

位图不是实际的数据类型,而是在 String 类型上定义的一组面向位的操作(更多信息请参阅 数据类型介绍页面的位图部分)。这意味着位图可以与字符串命令一起使用,最重要的是与 SET 和 GET 一起使用。

由于 Redis 的字符串是二进制安全的,因此位图可以简单地编码为字节流。字符串的第一个字节对应于位图的偏移量 0..7,第二个字节对应于 8..15 范围,依此类推。

例如,设置一些位后,获取位图的字符串值将如下所示:

> SETBIT bitmapsarestrings 2 1
> SETBIT bitmapsarestrings 3 1
> SETBIT bitmapsarestrings 5 1
> SETBIT bitmapsarestrings 10 1
> SETBIT bitmapsarestrings 11 1
> SETBIT bitmapsarestrings 14 1
> GET bitmapsarestrings
"42"

通过获取位图的字符串表示形式,客户端可以通过使用其本机编程语言中的本机位操作提取位值来解析响应的字节。对称地,还可以通过在客户端中执行位到字节编码并使用结果字符串调用 SET 来设置整个位图。

模式:设置多个位

SETBIT 擅长设置单个位,当需要设置多个位时可以多次调用。要优化此操作,您可以将多个 SETBIT 调用替换为对变量 BITFIELD 命令的单个调用以及使用 u1 类型的字段。

例如,上面的例子可以替换为:

> BITFIELD bitsinabitmap SET u1 2 1 SET u1 3 1 SET u1 5 1 SET u1 10 1 SET u1 11 1 SET u1 14 1

高级模式:访问位图范围

还可以使用 GETRANGE 和 SETRANGE 字符串命令来有效访问位图中的一系列位偏移量。下面是一个惯用的 Redis Lua 脚本实现示例,可以使用 EVAL 命令运行:

--[[
Sets a bitmap range

Bitmaps are stored as Strings in Redis. A range spans one or more bytes,
so we can call [`SETRANGE`](/content/commands/setrange.md) when entire bytes need to be set instead of flipping
individual bits. Also, to avoid multiple internal memory allocations in
Redis, we traverse in reverse.
Expected input:
  KEYS[1] - bitfield key
  ARGV[1] - start offset (0-based, inclusive)
  ARGV[2] - end offset (same, should be bigger than start, no error checking)
  ARGV[3] - value (should be 0 or 1, no error checking)
]]--

-- A helper function to stringify a binary string to semi-binary format
local function tobits(str)
  local r = ''
  for i = 1, string.len(str) do
    local c = string.byte(str, i)
    local b = ' '
    for j = 0, 7 do
      b = tostring(bit.band(c, 1)) .. b
      c = bit.rshift(c, 1)
    end
    r = r .. b
  end
  return r
end

-- Main
local k = KEYS[1]
local s, e, v = tonumber(ARGV[1]), tonumber(ARGV[2]), tonumber(ARGV[3])

-- First treat the dangling bits in the last byte
local ms, me = s % 8, (e + 1) % 8
if me > 0 then
  local t = math.max(e - me + 1, s)
  for i = e, t, -1 do
    redis.call('SETBIT', k, i, v)
  end
  e = t
end

-- Then the danglings in the first byte
if ms > 0 then
  local t = math.min(s - ms + 7, e)
  for i = s, t, 1 do
    redis.call('SETBIT', k, i, v)
  end
  s = t + 1
end

-- Set a range accordingly, if at all
local rs, re = s / 8, (e + 1) / 8
local rl = re - rs
if rl > 0 then
  local b = '\255'
  if 0 == v then
    b = '\0'
  end
  redis.call('SETRANGE', k, rs, string.rep(b, rl))
end

注意: 从位图中获取一系列位偏移量的实现留给读者作为练习。

Redis Software 与 Redis Cloud 兼容性

Redis
软件
Redis
Cloud
说明
✅ 标准
✅ 主动-主动
✅ 标准
✅ 主动-主动

返回值

RESP2

整数回复:偏移量 中存储的原始位值。

RESP3

整数回复:偏移量 中存储的原始位值。

资料来源:Redis 官方 SETBIT 文档;中文内容参考 Redis 文档许可。