redis+lua实现扣减库存

redis+lua实现扣减库存

柳性安 3,223 2023-01-07

redis+lua实现扣减库存

前言

在项目当中,某种商品的存量一定,当用户通过一定的方法获取这些库存时,应当由系统扣减掉对应的数量,此时如果出现并发,其实也很容易出现并发,那么直接由系统请求数据库查询库存再扣减的逻辑会造成很大的问题,会出现”超卖“现象。

如何解决呢,这里给出一个方案:使用redis扣减库存
库存信息写入redis,用户消费库存系统去redis查询信息,并执行扣减逻辑,此时如果并发大,也会出现超卖现象,因为扣减操作不是原子性的,如果要保证原子性,则需要引入lua脚本,下面给出我找到并修改的一个方案:

lua脚本

local key = KEYS[1]
local usedstore = tonumber(redis.call('get', key))
if usedstore ~= nil and usedstore > 0 then
    local current = tonumber(redis.call('decr', key))
    return current
end
--若此时库存为0,则直接返回-1,不写redis;在库存不足时减小写压力(1次扣减 + 1次回滚)
if usedstore ~= nil and usedstore == 0 then
    return -1
end
return usedstore

解析一下

get读取自定义的key值,tonumber转为数字,用变量usedstore 保存起来,usedstore 的值不等于(~=)默认值(nil),同时,usedstore 大于0,则调用‘decr’命令,减去key对应的value,即扣减库存;end结束if操作;
如果usedstore 不为nil 且 usedstore 为0,则返回-1,我定义的是,返回小于0的值表示扣减失败,回滚事务,否则返回当前的库存数usedstore。

lua脚本解析不完全正确,大致意思是这样,对我来说能达到想要的目的就行了,望谅解

附回滚操作

local key = KEYS[1]
local usedstore = tonumber(redis.call('get', key))
if usedstore ~= nil and usedstore > -1 then
    local current = tonumber(redis.call('incr', key))
    return current
end
return usedstore

主要是incr自增命令