Redis 的五种数据类型以及使用场景

一、Redis的五种数据类型

1. 字符串类型

a. 用途

  • 存储字符串类型数据,包括文本、数字等。

b. 常用命令

  • SET key value:设置键值对
  • GET key:获取指定键的值
  • INCR key:将键对应的值加1
  • DECR key:将键对应的值减1

示例代码:

import redis

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

# 设置键值对
r.set('name', 'Lucy')

# 获取键对应的值
print(r.get('name'))

# 值加1
r.incr('age')

# 值减1
r.decr('age')

2. 哈希类型

a. 用途

  • 存储一些具有对应关系的数据,比如用户信息。

b. 常用命令

  • HSET key field value:设置哈希类型数据中某个域的值
  • HGET key field:获取哈希类型数据中某个域的值
  • HGETALL key:获取哈希类型数据中所有域和值

示例代码:

import redis

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

# 设置哈希类型数据
r.hset('user', 'name', 'Lucy')
r.hset('user', 'age', 18)

# 获取哈希类型数据中某个域的值
print(r.hget('user', 'name'))

# 获取哈希类型数据中所有域和值
print(r.hgetall('user'))

3. 列表类型

a. 用途

  • 存储一组有序的字符串类型数据,可以用于实现消息队列、任务列表等场景。

b. 常用命令

  • LPUSH key value:从列表左侧插入一个值
  • RPUSH key value:从列表右侧插入一个值
  • LPOP key:从列表左侧弹出一个值
  • RPOP key:从列表右侧弹出一个值

示例代码:

import redis

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

# 向列表左侧插入两个值
r.lpush('task', 'task1')
r.lpush('task', 'task2')

# 向列表右侧插入一个值
r.rpush('task', 'task3')

# 从列表左侧弹出一个值
print(r.lpop('task'))

# 从列表右侧弹出一个值
print(r.rpop('task'))

4. 集合类型

a. 用途

  • 存储一组无序的字符串类型数据,常用于去重和快速判断某元素是否存在集合中。

b. 常用命令

  • SADD key member:向集合中添加一个元素
  • SMEMBERS key:获取集合中所有元素
  • SISMEMBER key member:判断某元素是否存在集合中

示例代码:

import redis

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

# 向集合中添加两个元素
r.sadd('students', 'Lucy', 'Jack')

# 获取集合中所有元素
print(r.smembers('students'))

# 判断某元素是否存在集合中
print(r.sismember('students', 'Lucy'))

5. 有序集合类型

a. 用途

  • 存储一组有序的字符串类型数据,每个元素都有一个对应的分数,可用于排行榜等场景。

b. 常用命令

  • ZADD key score member:向有序集合中添加一个元素和分数
  • ZRANGEBYSCORE key min max:返回有序集合中分数在给定区间内的所有元素
  • ZREVRANGE key start stop [WITHSCORES]:返回有序集合中按照分数从大到小排序的一部分元素,可选择同时返回分数

示例代码:

import redis

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

# 向有序集合中添加三个元素和分数
r.zadd('score', {
    
    'Lucy': 90, 'Jack': 85, 'Mike': 92})

# 返回有序集合中分数在给定区间内的所有元素
print(r.zrangebyscore('score', min=85, max=92))

# 返回有序集合中按照分数从大到小排序的一部分元素,并返回分数
print(r.zrevrange('score', start=0, stop=1, withscores=True))

二、Redis的使用场景

Redis 是一个高效的键值对数据库,因其速度快、支持丰富的数据类型和灵活的配置而被广泛应用于以下五种场景:

1. 缓存系统

Redis 可以将常用的数据存储在内存中,并且设置过期时间来实现缓存的功能。当应用需要这些数据时,可以直接从 Redis 中获取,避免了从磁盘读取数据的IO操作,从而提高了系统的响应时间和吞吐量。

# 以字符串类型为例,在 Python 中使用 Redis 实现缓存功能的示例代码
import redis

# 创建 Redis 客户端
redis_client = redis.Redis(host='localhost', port=6379, db=0)

def get_data_from_cache(key):
    """
    从 Redis 的缓存中获取数据
    """
    data = redis_client.get(key)
    if data is not None:
        # 如果缓存中存在对应 key 的数据,则直接返回
        return data
        
    # 如果缓存中不存在对应 key 的数据,则去数据库中查询并写入缓存
    data = fetch_data_from_database(key)
    redis_client.set(key, data, ex=3600)  # 设置过期时间为 1 小时
    return data

2. 计数器

Redis 的incr/decr命令可以对一个key进行原子性自增/自减操作,因此经常被用作计数器。比如统计网站访问量、商品的销量、评论的点赞数等。

# 在 Python 中使用 Redis 的 incr/decr 实现计数器功能的示例代码
def increase_counter(key):
    """
    自增一个计数器,返回自增后的值
    """
    return redis_client.incr(key)

def decrease_counter(key):
    """
    自减一个计数器,返回自减后的值
    """
    return redis_client.decr(key)

3. 消息队列

Redis提供了消息队列功能,可以作为轻量级的消息中间件使用,支持多个生产者和消费者。生产者可以使用lpush或rpush向一个列表插入消息,而消费者则使用blpop或brpop从列表中弹出消息并进行处理。

# 在 Python 中使用 Redis 实现消息队列功能的示例代码

import threading
import time

def produce_message(queue_name: str):
    """
    生产者向队列中插入消息
    """
    for i in range(10):
        message = f"Message {i}"
        redis_client.lpush(queue_name, message)  # 左边插入消息
        print(f"Produce Message: {message}")
        time.sleep(0.5)

def consume_message(queue_name: str):
    """
    消费者从队列中弹出消息并进行处理
    """
    while True:
        message = redis_client.brpop(queue_name, timeout=3)  # 从右边弹出消息
        if message is not None:
            print(f"Consume Message: {message[1].decode()}")

# 创建生产者和消费者线程
t1 = threading.Thread(target=produce_message, args=('my_queue',))
t2 = threading.Thread(target=consume_message, args=('my_queue',))

# 启动线程
t1.start()
t2.start()

# 等待线程结束
t1.join()
t2.join()

4. 排行榜系统

Redis提供有序集合(SortedSet)结构,支持按照某个字段为成员进行排序,因此可以用来实现排行榜系统。比如统计音乐的播放次数、新闻的阅读量、用户的积分排名等。

# 在 Python 中使用 Redis 实现排行榜系统的示例代码

def update_ranking(username: str, score: float):
    """
    更新排行榜,以 username 为成员、score 为排序指标
    """
    redis_client.zadd('ranking', {
    
    username: score})

def get_top_n(n: int):
    """
    获取排行榜前 n 名
    """
    return redis_client.zrevrangebyscore('ranking', '+inf', '-inf', start=0, num=n, withscores=True)

5. 分布式锁

Redis的setnx命令可以在key不存在时设置key的值,因此可以基于此实现分布式锁。一个进程在执行加锁操作时,先尝试使用setnx占据锁的key,如果返回值为1,表示获得了锁;否则表示锁已被其他进程占据,等待一段时间后再次尝试。加锁和解锁操作需要使用相同的key和value才能成功。

# 在 Python 中使用 Redis 实现分布式锁的示例代码

def acquire_lock_with_timeout(lockname: str, acquire_timeout: int=10):
    """
    获取分布式锁,等待 acquire_timeout 秒后仍未获得锁则放弃
    """
    identifier = str(uuid.uuid4())
    end = time.time() + acquire_timeout
    
    while time.time() < end:
        if redis_client.setnx(lockname, identifier):
            # 成功获取到锁
            return identifier
        elif not redis_client.ttl(lockname):
            # 如果锁没有设置过期时间,则设置一个过期时间,避免死锁
            redis_client.expire(lockname, 10)
            
        # 等待一段时间后进行重试
        time.sleep(0.1)
        
    return False

def release_lock(lockname: str, identifier: str):
    """
    释放分布式锁,需要传入获取锁时返回的 identifier
    """
    pipline = redis_client.pipeline(True)
    while True:
        try:
            # 监视锁,保证在执行事务期间锁没有被其他进程修改
            pipline.watch(lockname)

            if pipline.get(lockname).decode() == identifier:
                # 删除锁
                pipline.multi()
                pipline.delete(lockname)
                pipline.execute()
                return True

            # 锁已被其他进程修改,放弃执行事务
            pipline.unwatch()
        except redis.exceptions.WatchError:
            # 如果在执行pipline.watch()和pipline.multi()之间,锁的值被其他进程改变,会抛出 WatchError 异常
            continue
        finally:
            pipline.reset()
    return False

猜你喜欢

转载自blog.csdn.net/u010349629/article/details/130895567