go go-redis 使用lua保证操作的原子性

   Redis是应对高并发的常用工具,在常用缓存技巧中讲过相关技巧。但有些业务场景,使用Redis会遇到问题,如电商里的秒杀、扣减库存等。

拿减库存举例,一般需要两步:

  • 先扣减库存,获取扣减后的库存值V

  • 如果V小于0,说明库存不够,需要将扣减的值再加回去;如果V大于等于0,则执行后续操作

但这两步是分开的,很可能扣减时成功,但增加回去时失败,导致库存不一致。

另一种方案是:

  • t1时刻,先查询库存,判断是否够用

  • t2时刻,再减库存

但这两步也是分开的,而且t1和t2有时间差,t2时刻扣减库存时,真正的库存和t1时刻已经不一致了。

那如何保证一致性呢?go-redis又如何来解决这个问题呢?

redis中lua基本介绍

   在Redis中通过lua脚本操作Redis,脚本会将多个命令和操作当成一个命令在Redis中执行,也就是说该脚本在执行的过程中,不会被任何其他脚本或命令打断干扰。正是因此这种原子性,lua脚本才可以代替multi和exec的事务功能。同时也是因此,在lua脚本中不宜进行过大的开销操作,避免影响后续的其他请求的正常执行。

go-redis中lua使用


     废话不多说,直接上代码!!!!!!!!

package main

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

var ctx = context.Background()

func main() {
    // 创建 Redis 客户端连接
    rdb := redis.NewClient(&redis.Options{
        Addr:     "localhost:6379", // Redis 服务器地址
        Password: "",               // Redis 访问密码,如果没有设置密码则为空字符串
        DB:       0,                // 选择数据库,默认为0
    })


    // 定义 Lua 脚本 
    luaScript := `
local key = KEYS[1]
local value = redis.call('GET', key)
if value then
    redis.call('INCR', key)
    return redis.call('GET', key)
else
    return redis.error_reply("key does not exist")
end
`

    // 初始化键的值
    rdb.Set(ctx, "mykey", 10, 0)

    // 执行 Lua 脚本
    result, err := rdb.Eval(ctx, luaScript, []string{"mykey"}).Result()
    if err != nil {
        fmt.Println("Lua script execution error:", err)
        return
    }

    // 输出 Lua 脚本执行结果
    fmt.Println("Script result:", result)
}

结论

    使用 go-redis 执行 Lua 脚本可以大大增强 Redis 的功能,确保数据操作的原子性和一致性,提高系统的性能和可靠性。通过这种方式,可以在 Redis 中实现更复杂的业务逻辑,同时简化客户端代码,提高系统的整体效率。

  • 16
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RedisLua脚本可以通过使用EVAL命令来实现原子性操作。通过将多个Redis命令组合在一个Lua脚本执行,可以确保这些命令在同一时间内被连续地执行,从而保证原子性。引用 在Lua脚本,可以使用redis.call()和redis.pcall()这个不同的函数来调用Redis命令。redis.call()函数用于执行普通的Redis命令,而redis.pcall()函数则用于执行Redis命令并处理错误。通过使用个函数,可以在Lua脚本执行多个Redis命令,并保证它们的原子性。引用 另外,Redis在执行Lua脚本时采用了单线程的方式,这意味着同一时间内只能执行一个Lua脚本,不会被其他脚本或Redis命令打断。因此,在执行Lua脚本期间,不会发生并发问题,从而保证原子性。引用 综上所述,通过将多个Redis命令组合在Lua脚本,并使用redis.call()和redis.pcall()函数来执行这些命令,结合Redis的单线程执行机制,可以保证Lua脚本的原子性操作。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Redis Lua脚本实现原子性操作](https://blog.csdn.net/kuishao1314aa/article/details/120367618)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值