redis的基础数据结构-list列表

1. redis的list数据结构

参考链接:https://mp.weixin.qq.com/s/srkd73bS2n3mjIADLVg72A
Redis 中的 List 数据结构是一个简单的字符串列表,可以在两端快速推入和弹出元素。List 的实现是双向链表,这使得它在插入和删除操作上非常高效。List 的元素可以是字符串类型,且可以重复。

1.1. list结构的特性

  • 有序:List 中的元素有顺序,元素按照插入的顺序进行排列。
  • 支持重复:同一个元素可以出现多次。
  • 双向操作:可以在两端进行插入和删除操作。

1.2. 常用命令

以下是一些常用的 Redis List 命令:

  1. LPUSH key value:在列表的左侧(头部)推入元素。
  2. RPUSH key value:在列表的右侧(尾部)推入元素。
  3. LPOP key:从列表的左侧弹出元素。
  4. RPOP key:从列表的右侧弹出元素。
  5. LRANGE key start stop:获取列表中指定范围的元素。
  6. LLEN key:获取列表的长度。
  7. LREM key count value:移除列表中指定数量的某个元素。
  8. LINSERT key BEFORE|AFTER pivot value:在列表中指定元素之前或之后插入一个新元素。
  9. LSET key index value:通过索引设置列表中的元素。
  10. LTRIM key start stop:修剪列表,只保留指定范围内的元素。
XXXXXX:6379> LPUSH user:1001:orders "order_1" #用户1001创建新订单order_1
(integer) 1
XXXXXX:6379> LPUSH user:1001:orders "order_2" #用户1001创建新订单order_2
(integer) 2
XXXXXX:6379> LPUSH user:1001:orders "order_3" #用户1001创建新订单order_3
(integer) 3
XXXXXX:6379> LRANGE user:1001:orders 0 -1 #用户1001查询所有订单
1) "order_3"
2) "order_2"
3) "order_1"
XXXXXX:6379> LLEN user:1001:orders #用户1001查询所有订单的数量
(integer) 3
XXXXXX:6379> LPOP user:1001:orders #用户1001取消最新的订单
"order_3"
XXXXXX:6379> LRANGE user:1001:orders 0 -1 #用户1001查询所有订单
1) "order_2"
2) "order_1"
XXXXXX:6379> LSET user:1001:orders 1 "order_1_completed" #订单order_1完成
OK
XXXXXX:6379> LRANGE user:1001:orders 0 -1 #用户1001查询所有订单
1) "order_2"
2) "order_1_completed"
XXXXXX:6379> LTRIM user:1001:orders 0 9 #用户修剪订单列表,只保留最近的 10 个订单
OK
XXXXXX:6379> LRANGE user:1001:orders 0 -1 #用户1001查询所有订单
1) "order_2"
2) "order_1_completed"
XXXXXX:6379> LREM user:1001:orders 1 "order_2" #用户移除订单order_2
(integer) 1
XXXXXX:6379> LRANGE user:1001:orders 0 -1 ##用户1001查询所有订单
1) "order_1_completed"
XXXXXX:6379> LINSERT user:1001:orders BEFORE "order_1_completed" "order_4" #用户在order_1前插入order_4
(integer) 2
XXXXXX:6379> LRANGE user:1001:orders 0 -1 ##用户1001查询所有订单
1) "order_4"
2) "order_1_completed"

2. 常见业务场景

2.1 消息队列

消息队列:List类型常用于实现消息队列,用于异步处理任务,如邮件发送队列、任务调度等。

案例讲解
背景

在一个电商平台中,用户下单后,系统需要执行多个异步任务,如订单处理、库存更新、发送确认邮件等
在这里插入图片描述

优势
  1. 异步处理:使用List作为消息队列,可以将任务异步化,提高用户体验和系统响应速度。
  2. 任务管理:方便地对任务进行管理和监控,如重试失败的任务、监控任务处理进度等。
  3. 系统解耦:各个任务处理模块可以独立运行,降低系统间的耦合度。
解决方案

使用Redis List类型存储和管理任务消息队列。

代码实现
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "github.com/go-redis/redis/v8"
    "log"
    "time"
)

var ctx = context.Background()

// Redis 客户端初始化
var redisClient = redis.NewClient(&redis.Options{
    Addr:     "localhost:6379",
    Password: "", // no password set
    DB:       0,  // use default DB
})

type Order struct {
    ID     string
    Amount float64
}

func (o Order) ToString() string {
    orderJSON, _ := json.Marshal(o)
    return string(orderJSON)
}

func addOrderToQueue(order Order) {
    // 将新订单添加到订单处理队列
    redisClient.LPush(ctx, "order_queue", order.ToString())
}

func getNextOrder() (Order, error) {
    // 从订单处理队列中获取待处理的订单
    orderJSON, err := redisClient.RPop(ctx, "order_queue").Result()
    if err != nil {
       return Order{}, err
    }
    var order Order
    err = json.Unmarshal([]byte(orderJSON), &order)
    if err != nil {
       return Order{}, err
    }
    return order, nil
}

func addInventoryUpdateToQueue(order Order) {
    // 将库存更新任务添加到库存更新队列
    redisClient.LPush(ctx, "inventory_update_queue", order.ToString())
}

func getNextInventoryUpdate() (Order, error) {
    // 从库存更新队列中获取待处理的更新
    updateJSON, err := redisClient.RPop(ctx, "inventory_update_queue").Result()
    if err != nil {
       return Order{}, err
    }
    var order Order
    err = json.Unmarshal([]byte(updateJSON), &order)
    if err != nil {
       return Order{}, err
    }
    return order, nil
}

func addEmailToQueue(order Order) {
    // 将邮件发送任务添加到邮件发送队列
    redisClient.LPush(ctx, "email_queue", order.ToString())
}

func getNextEmail() (Order, error) {
    // 从邮件发送队列中获取待发送邮件的订单
    emailJSON, err := redisClient.RPop(ctx, "email_queue").Result()
    if err != nil {
       return Order{}, err
    }
    var order Order
    err = json.Unmarshal([]byte(emailJSON), &order)
    if err != nil {
       return Order{}, err
    }
    return order, nil
}

func processOrder(order Order) {
    // 处理订单逻辑
    fmt.Printf("Processing order: %s\n", order.ID)

    // 添加库存更新任务
    addInventoryUpdateToQueue(order)

    // 添加邮件发送任务
    addEmailToQueue(order)

    // 模拟处理时间
    time.Sleep(1 * time.Second)
}

func updateInventory(order Order) {
    // 更新库存逻辑
    fmt.Printf("Updating inventory for order: %s\n", order.ID)
    // 模拟更新库存的操作
    time.Sleep(1 * time.Second)
}

func sendEmail(order Order) {
    // 发送确认邮件逻辑
    fmt.Printf("Sending confirmation email for order: %s\n", order.ID)
    // 模拟发送邮件的操作
    time.Sleep(1 * time.Second)
}

2.2 排行榜

排行榜:使用List类型,可以存储和管理如游戏得分、文章点赞数等排行榜数据。

案例讲解
背景

在一个社交平台中,用户发表的文章根据点赞数进行排名,需要实时更新和展示排行榜。
在这里插入图片描述

优势
  1. 实时性:能够快速响应用户的点赞行为,实时更新排行榜。
  2. 排序功能:利用LRANGE命令,可以方便地获取指定范围内的排行榜数据。
解决方案

使用Redis List类型存储用户的得分或点赞数,并根据需要对List进行排序。

代码实现
package main

import (
    "context"
    "fmt"
    "github.com/go-redis/redis/v8"
    "log"
)

var ctx = context.Background()

// Redis 客户端初始化
var redisClient = redis.NewClient(&redis.Options{
    Addr:     "localhost:6379",
    Password: "", // no password set
    DB:       0,  // use default DB
})

type Article struct {
    ID    string
    Score int64
}

// 为文章点赞,更新排行榜
func likeArticle(articleID string) {
    // 假设每个文章都有一个对应的得分,使用 Sorted Set 来维护
    redisClient.ZIncrBy(ctx, "article_rankings", 1, articleID)
}

// 获取文章排行榜
func getArticleRankings() ([]Article, error) {
    // 使用 ZREVRANGE 获取得分最高的文章
    result, err := redisClient.ZRevRangeWithScores(ctx, "article_rankings", 0, -1).Result()
    if err != nil {
       return nil, err
    }

    articles := []Article{}
    for _, z := range result {
       articles = append(articles, Article{
          ID:    z.Member.(string),
          Score: int64(z.Score),
       })
    }
    return articles, nil
}

3. 注意事项:

List类型在列表元素数量较大时,操作可能会变慢,需要考虑性能优化。

  • 在使用List实现队列时,要注意处理消息的顺序和丢失问题。
  • 可以使用BRPOP或BLPOP命令在多个列表上进行阻塞式读取,适用于多消费者场景。
  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SAO&asuna

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值