MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Redis键命令详解与实战应用

2024-03-242.8k 阅读

Redis 键命令基础

Redis 作为一款高性能的键值对数据库,键(Key)是其数据结构中至关重要的组成部分。键命令用于对 Redis 中的键进行各种操作,比如创建、删除、查询等。

键的命名规范

在 Redis 中,键的命名没有严格的语法限制,但为了保持良好的可读性和维护性,通常遵循一些约定。一般建议键名采用有意义的字符串,比如以业务模块和具体含义进行命名,例如 “user:1:profile” 表示用户 ID 为 1 的用户资料。避免使用过长或过于复杂的键名,以免增加网络传输和存储成本。同时,要注意键名的唯一性,因为 Redis 中相同的键会覆盖之前的值。

通用键命令

  1. DEL 命令
    • 作用:用于删除一个或多个键。
    • 语法DEL key [key ...]
    • 示例(Python 代码)
import redis

r = redis.Redis(host='localhost', port=6379, db = 0)
r.set('test_key', 'test_value')
result = r.delete('test_key')
print(result)

在上述代码中,首先使用 set 命令设置了一个键值对,然后使用 DEL 命令删除该键,并打印删除操作返回的结果。DEL 命令返回被删除键的数量,如果键不存在,返回 0。

  1. EXISTS 命令
    • 作用:检查一个或多个键是否存在。
    • 语法EXISTS key [key ...]
    • 示例(Python 代码)
import redis

r = redis.Redis(host='localhost', port=6379, db = 0)
r.set('test_key', 'test_value')
exists_result = r.exists('test_key')
print(exists_result)

这段代码先设置了一个键值对,然后使用 EXISTS 命令检查键是否存在,EXISTS 命令返回存在键的数量,如果键存在返回 1,不存在返回 0。

  1. TYPE 命令
    • 作用:返回键所存储的值的类型。
    • 语法TYPE key
    • 示例(Python 代码)
import redis

r = redis.Redis(host='localhost', port=6379, db = 0)
r.set('test_key', 'test_value')
type_result = r.type('test_key')
print(type_result.decode('utf - 8'))

代码中设置键值对后,通过 TYPE 命令获取键值的类型,由于 Redis - Python 客户端返回的是字节类型,所以使用 decode 方法将其转换为字符串类型并打印。常见的返回类型有 string(字符串)、hash(哈希)、list(列表)、set(集合)和 zset(有序集合)。

键的生存时间(TTL)相关命令

Redis 允许为键设置生存时间(Time - To - Live,TTL),即键在指定时间后会自动过期并被删除。这在很多场景下非常有用,比如缓存数据的自动清理。

SETEX 命令

  1. 作用:设置一个键值对,并同时设置键的生存时间(以秒为单位)。
  2. 语法SETEX key seconds value
  3. 示例(Python 代码)
import redis
import time

r = redis.Redis(host='localhost', port=6379, db = 0)
r.setex('test_key', 10, 'test_value')
time.sleep(5)
ttl_result = r.ttl('test_key')
print(ttl_result)

上述代码使用 SETEX 命令设置了一个键 test_key,其值为 test_value,生存时间为 10 秒。然后通过 time.sleep 暂停 5 秒,再使用 TTL 命令获取键剩余的生存时间并打印。

EXPIRE 命令

  1. 作用:为一个已经存在的键设置生存时间(以秒为单位)。
  2. 语法EXPIRE key seconds
  3. 示例(Python 代码)
import redis
import time

r = redis.Redis(host='localhost', port=6379, db = 0)
r.set('test_key', 'test_value')
r.expire('test_key', 10)
time.sleep(5)
ttl_result = r.ttl('test_key')
print(ttl_result)

这里先使用 SET 命令设置键值对,然后使用 EXPIRE 命令为该键设置 10 秒的生存时间,同样暂停 5 秒后获取剩余生存时间并打印。

PEXPIRE 命令

  1. 作用:与 EXPIRE 类似,但设置的生存时间是以毫秒为单位。
  2. 语法PEXPIRE key milliseconds
  3. 示例(Python 代码)
import redis
import time

r = redis.Redis(host='localhost', port=6379, db = 0)
r.set('test_key', 'test_value')
r.pexpire('test_key', 10000)  # 设置 10000 毫秒(10 秒)的生存时间
time.sleep(5)
ttl_result = r.pttl('test_key')
print(ttl_result)

这段代码展示了使用 PEXPIRE 命令设置以毫秒为单位的生存时间,并通过 PTTL 命令获取剩余毫秒数的生存时间。

TTL 与 PTTL 命令

  1. 作用TTL 命令用于获取键的剩余生存时间(以秒为单位),PTTL 命令用于获取键的剩余生存时间(以毫秒为单位)。如果键不存在或没有设置生存时间,TTL 返回 -1,PTTL 返回 -1。如果键已过期,TTLPTTL 都返回 -2。
  2. 语法TTL keyPTTL key
  3. 示例(Python 代码)
import redis
import time

r = redis.Redis(host='localhost', port=6379, db = 0)
r.setex('test_key', 10, 'test_value')
time.sleep(5)
ttl_result = r.ttl('test_key')
pttl_result = r.pttl('test_key')
print(f"TTL: {ttl_result}, PTTL: {pttl_result}")

此代码先设置一个有 10 秒生存时间的键,暂停 5 秒后,分别使用 TTLPTTL 命令获取剩余生存时间并打印。

键的通配符操作

在 Redis 中,可以使用通配符来匹配多个键,这在批量操作键时非常方便。

KEYS 命令

  1. 作用:查找所有符合给定模式(pattern)的键。
  2. 语法KEYS pattern
  3. 通配符说明
    • *:匹配任意数量的字符,包括 0 个字符。例如,user:* 可以匹配 user:1user:2 等所有以 user: 开头的键。
    • ?:匹配任意单个字符。例如,user:? 可以匹配 user:1user:a 等,但不能匹配 user:12
    • []:匹配指定范围内的单个字符。例如,user:[1 - 5] 可以匹配 user:1user:2user:3user:4user:5
  4. 示例(Python 代码)
import redis

r = redis.Redis(host='localhost', port=6379, db = 0)
r.set('user:1', 'data1')
r.set('user:2', 'data2')
r.set('product:1', 'product_data1')
keys_result = r.keys('user:*')
print([key.decode('utf - 8') for key in keys_result])

代码中设置了几个键,然后使用 KEYS 命令通过通配符 user:* 查找所有以 user: 开头的键,并将结果转换为字符串列表打印。

需要注意的是,KEYS 命令在生产环境中应谨慎使用,因为它会遍历整个数据库,在键数量较多时可能会影响 Redis 的性能。

SCAN 命令

  1. 作用:用于增量迭代数据库中的键。它可以避免 KEYS 命令在大数据量时的性能问题。
  2. 语法SCAN cursor [MATCH pattern] [COUNT count]
    • cursor:游标,初始值为 0,每次迭代返回的游标用于下一次迭代。当游标返回 0 时,表示迭代结束。
    • MATCH pattern:可选参数,用于指定匹配的模式,与 KEYS 命令中的通配符用法类似。
    • COUNT count:可选参数,用于指定每次迭代返回的键的数量,默认值为 10。但实际返回的键数量可能小于该值。
  3. 示例(Python 代码)
import redis

r = redis.Redis(host='localhost', port=6379, db = 0)
r.set('user:1', 'data1')
r.set('user:2', 'data2')
r.set('product:1', 'product_data1')

cursor = '0'
while cursor!= 0:
    cursor, keys = r.scan(cursor=cursor, match='user:*', count = 10)
    print([key.decode('utf - 8') for key in keys])

上述代码通过 SCAN 命令迭代查找所有以 user: 开头的键,每次迭代获取最多 10 个键,直到游标为 0 表示迭代结束。

键的移动与重命名

在 Redis 中,可以对键进行移动和重命名操作,这在数据整理和重构时非常有用。

MOVE 命令

  1. 作用:将当前数据库中的键移动到另一个数据库。
  2. 语法MOVE key db
    • key:要移动的键。
    • db:目标数据库的编号。Redis 默认有 16 个数据库,编号从 0 到 15。
  3. 示例(Python 代码)
import redis

r1 = redis.Redis(host='localhost', port=6379, db = 0)
r2 = redis.Redis(host='localhost', port=6379, db = 1)
r1.set('test_key', 'test_value')
move_result = r1.move('test_key', 1)
exists_result = r2.exists('test_key')
print(f"Move result: {move_result}, Exists in db1: {exists_result}")

这段代码首先在数据库 0 中设置了一个键值对,然后使用 MOVE 命令将键移动到数据库 1,最后检查数据库 1 中该键是否存在。如果键移动成功,MOVE 命令返回 1,否则返回 0。

RENAME 命令

  1. 作用:修改键的名称。
  2. 语法RENAME key newkey
    • key:要修改名称的键。
    • newkey:新的键名。如果 newkey 已经存在,它将被覆盖。
  3. 示例(Python 代码)
import redis

r = redis.Redis(host='localhost', port=6379, db = 0)
r.set('old_key', 'test_value')
rename_result = r.rename('old_key', 'new_key')
exists_result = r.exists('new_key')
print(f"Rename result: {rename_result}, Exists new key: {exists_result}")

此代码先设置一个键 old_key,然后使用 RENAME 命令将其重命名为 new_key,并检查 new_key 是否存在。RENAME 命令执行成功返回 True,否则返回 False

RENAMENX 命令

  1. 作用:与 RENAME 类似,但只有当 newkey 不存在时才会执行重命名操作。
  2. 语法RENAMENX key newkey
  3. 示例(Python 代码)
import redis

r = redis.Redis(host='localhost', port=6379, db = 0)
r.set('old_key', 'test_value')
renamenx_result = r.renamenx('old_key', 'new_key')
exists_result = r.exists('new_key')
print(f"RENAMENX result: {renamenx_result}, Exists new key: {exists_result}")

这段代码展示了 RENAMENX 命令的使用,由于第一次执行 RENAMENXnew_key 不存在,重命名操作成功。如果再次执行 RENAMENX 操作,由于 new_key 已经存在,重命名将失败。RENAMENX 命令执行成功返回 1,失败返回 0。

键命令的实战应用场景

  1. 缓存数据管理
    • 在 Web 应用中,经常使用 Redis 作为缓存。通过设置键的生存时间,可以实现缓存数据的自动过期。例如,对于一些不经常变化的页面数据,可以将其缓存到 Redis 中,并设置一个合适的生存时间。当缓存过期后,应用程序会重新从数据源获取数据并更新缓存。
    • 示例(Python Flask 应用)
from flask import Flask
import redis
import time

app = Flask(__name__)
r = redis.Redis(host='localhost', port=6379, db = 0)


@app.route('/')
def index():
    cached_data = r.get('page_data')
    if cached_data:
        return cached_data.decode('utf - 8')
    else:
        real_data = "This is real data from database"
        r.setex('page_data', 3600, real_data)  # 设置 1 小时的缓存时间
        return real_data


if __name__ == '__main__':
    app.run(debug = True)

在上述 Flask 应用中,每次请求首页时,先检查 Redis 中是否有缓存数据(键为 page_data)。如果有,则直接返回缓存数据;如果没有,则从数据库获取真实数据(这里简单模拟为一个字符串),将其缓存到 Redis 并设置 1 小时的生存时间,然后返回真实数据。

  1. 用户会话管理
    • 在 Web 应用的用户会话管理中,Redis 可以用来存储用户的会话信息。每个用户的会话可以用一个唯一的键表示,键的值可以是包含用户信息的哈希表。通过设置会话键的生存时间,可以实现会话的自动过期,提高安全性。
    • 示例(Python 代码)
import redis
import uuid

r = redis.Redis(host='localhost', port=6379, db = 0)


def create_session(user_id):
    session_id = str(uuid.uuid4())
    session_key = f'session:{session_id}'
    user_info = {'user_id': user_id, 'username': 'example_user'}
    r.hmset(session_key, user_info)
    r.expire(session_key, 3600)  # 设置 1 小时的会话时间
    return session_id


def get_session(session_id):
    session_key = f'session:{session_id}'
    session_data = r.hgetall(session_key)
    if session_data:
        return {key.decode('utf - 8'): value.decode('utf - 8') for key, value in session_data.items()}
    return None


session_id = create_session(1)
print(f"Created session ID: {session_id}")
retrieved_session = get_session(session_id)
print(f"Retrieved session: {retrieved_session}")

这段代码展示了如何创建和获取用户会话。create_session 函数生成一个唯一的会话 ID,创建一个会话键,并将用户信息存储为哈希表,同时设置 1 小时的生存时间。get_session 函数根据会话 ID 获取会话信息。

  1. 分布式锁实现
    • Redis 可以用于实现分布式锁。通过使用 SETNX(SET if Not eXists)命令设置一个锁键,如果设置成功,则表示获取到锁;如果设置失败,则表示锁已被其他进程占用。可以为锁键设置一个生存时间,以防止死锁。
    • 示例(Python 代码)
import redis
import time

r = redis.Redis(host='localhost', port=6379, db = 0)


def acquire_lock(lock_key, lock_value, expire_time = 10):
    result = r.set(lock_key, lock_value, nx = True, ex = expire_time)
    return result


def release_lock(lock_key, lock_value):
    pipe = r.pipeline()
    while True:
        try:
            pipe.watch(lock_key)
            if pipe.get(lock_key) == lock_value.encode('utf - 8'):
                pipe.multi()
                pipe.delete(lock_key)
                pipe.execute()
                return True
            pipe.unwatch()
            break
        except redis.WatchError:
            continue
    return False


lock_key = 'distributed_lock'
lock_value = str(uuid.uuid4())
if acquire_lock(lock_key, lock_value):
    try:
        print("Lock acquired, doing some work...")
        time.sleep(5)
    finally:
        release_lock(lock_key, lock_value)
        print("Lock released")
else:
    print("Failed to acquire lock")

在上述代码中,acquire_lock 函数尝试获取分布式锁,release_lock 函数用于释放锁。在获取到锁后,模拟进行一些工作,然后释放锁。通过设置锁键的生存时间,可以避免因程序异常导致的死锁情况。

  1. 排行榜实现
    • 使用 Redis 的有序集合(Sorted Set)数据结构结合键命令,可以实现排行榜功能。每个排行榜可以用一个键表示,有序集合中的成员为排行榜的参与者,分数为其对应的排名分数。
    • 示例(Python 代码)
import redis

r = redis.Redis(host='localhost', port=6379, db = 0)


def add_score(player, score, leaderboard_key):
    r.zadd(leaderboard_key, {player: score})


def get_leaderboard(leaderboard_key, start = 0, end = -1):
    leaderboard = r.zrevrange(leaderboard_key, start, end, withscores = True)
    return [(player.decode('utf - 8'), score) for player, score in leaderboard]


leaderboard_key = 'game_leaderboard'
add_score('Player1', 100, leaderboard_key)
add_score('Player2', 80, leaderboard_key)
add_score('Player3', 120, leaderboard_key)
leaderboard = get_leaderboard(leaderboard_key)
print("Leaderboard:", leaderboard)

此代码展示了如何实现一个简单的游戏排行榜。add_score 函数用于向排行榜中添加玩家的分数,get_leaderboard 函数用于获取排行榜信息。通过有序集合的特性,排行榜会根据分数自动排序。

通过对 Redis 键命令的深入理解和在不同场景下的应用,可以充分发挥 Redis 的高性能和灵活性,为各种应用提供强大的数据存储和管理支持。无论是缓存、会话管理、分布式锁还是排行榜等功能,键命令都起着关键的作用,帮助开发者构建高效、可靠的应用程序。在实际应用中,需要根据具体的业务需求和性能要求,合理选择和组合键命令,以达到最佳的效果。同时,要注意在高并发和大数据量环境下,键命令的性能影响,比如避免频繁使用 KEYS 命令等,确保 Redis 数据库的稳定运行。