最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Redis增減庫存避坑的實現(xiàn)

 更新時間:2024年02月26日 11:29:03   作者:封閉火車  
在電商平臺或者倉庫管理系統(tǒng)中,庫存的管理是非常重要的一項任務(wù),本文主要介紹了Redis增減庫存避坑的實現(xiàn),具有一定的參考價值,感興趣的可以了解一下

Redis實現(xiàn)庫存管理

查詢商品庫存數(shù)量

首先,我們可以使用Redis的String類型來存儲商品的庫存數(shù)量。每個商品對應(yīng)一個key,其值為庫存數(shù)量。當(dāng)需要查詢商品庫存數(shù)量時,只需要獲取相應(yīng)key的值即可。

# 獲取商品庫存數(shù)量
def get_stock(product_id):
    redis_conn = Redis()
    stock = redis_conn.get(f'stock:{product_id}')
    return int(stock) if stock else 0

更新商品庫存數(shù)量

當(dāng)有人購買商品時,我們需要更新商品的庫存數(shù)量。為了保證庫存的準(zhǔn)確性,我們可以使用Redis的原子操作INCRBY或者DECRBY來實現(xiàn)庫存數(shù)量的增減。

# 更新商品庫存數(shù)量
def update_stock(product_id, quantity):
    redis_conn = Redis()
    redis_conn.incrby(f'stock:{product_id}', quantity)

判斷商品庫存是否充足

為了判斷商品庫存是否充足,我們只需要查詢商品的庫存數(shù)量并與購買數(shù)量進行比較即可。

# 判斷商品庫存是否充足
def check_stock(product_id, quantity):
    stock = get_stock(product_id)
    return stock >= quantity

避免超賣問題

在高并發(fā)的情況下,可能會出現(xiàn)超賣問題,即多個用戶同時購買了同一件商品,導(dǎo)致庫存數(shù)量出現(xiàn)負(fù)數(shù)。為了避免這個問題,我們可以使用Redis的WATCH機制來保證庫存數(shù)量的原子性。

# 避免超賣問題
def avoid_over_sell(product_id, quantity):
    redis_conn = Redis()
    with redis_conn.pipeline() as pipe:
        while True:
            try:
                pipe.watch(f'stock:{product_id}')
                stock = pipe.get(f'stock:{product_id}')
                stock = int(stock) if stock else 0
                if stock < quantity:
                    pipe.unwatch()
                    raise Exception('庫存不足')
                pipe.multi()
                pipe.decrby(f'stock:{product_id}', quantity)
                pipe.execute()
                break
            except WatchError:
                continue

問題

先執(zhí)行g(shù)et獲取值,判斷符合條件再執(zhí)行incr、decr操作。在臨界緩存失效的情況下,會默認(rèn)賦值當(dāng)前key為永不過期的0,再執(zhí)行加減法,導(dǎo)致程序異常。

推薦解決方案

1、限制接口頻率:先incr,執(zhí)行后值為1,說明是第一次執(zhí)行,需要額外設(shè)置過期時間,再判斷是否超過當(dāng)前接口頻率限制(注意上述步驟不可調(diào)換順序)

2、使用lua腳本完整提交一次操作,腳本中的key可以保證一致。以加減庫存為例,先查詢key存在的情況下,再進行庫存變更,如果不存在無需處理,等待下次緩存加載即為最新的值

問題描述

場景1:我們緩存了一個商品的庫存,過期時間為5分鐘,根據(jù)用戶的購買和取消執(zhí)行 incr、decr 操作。代碼通常會這樣來編寫:

		// 庫存存在則加一
        if(redisService.get(prefix, key, Integer.class) != null){
            redisService.incr(prefix, key);
        }

場景2:對訪問頻次進行限流,我們可以通過redis簡單實現(xiàn):

        // 首先獲取當(dāng)前訪問頻次
		Integer count = redisService.get(prefix, key, Integer.class);
        // 如果頻次為空,則設(shè)置訪問次數(shù)為1
		if (count == null) {
            redisService.set(prefix, key, 1);
        } else if (count < checkFrequencyCount) {
            // 如果頻次小于限制,則設(shè)置訪問次數(shù)加1
            redisService.incr(prefix, key);
        } else {
			// 如果頻次超過限制,則限流
            throw new AppException("訪問頻次過高,請稍候再試");
        }

兩種場景編碼看似都沒有問題,但實際運行中卻發(fā)現(xiàn)redis中有一些key變成了永不過期的key,而且值不正確。

原因是: 因為redis的incr操作,當(dāng)key不存在時, 會生成這個key并將值初始化為0, 并且默認(rèn)設(shè)置key的有效時間為永久。

解決方案

1.優(yōu)化Java代碼,例如場景2。不論這個key是否存在都先加一,然后判斷其過期時間是否為永不過期,如果是永不過期則說明是新生成的key,給它設(shè)置過期時間即可,如果非永不過期則無需操作。最后再判斷一下是否值已經(jīng)大于訪問頻次了,是則限流。

		long count = redisService.incr(prefix, key);
		// 判斷必須放在后面,否則key沒有過期時間永遠(yuǎn)無法清除
        long expire = redisService.ttl(prefix, key);
        if (expire == -1) {
            redisService.setExpire(prefix, key, accessExpireSecond);
        }
        if (count > checkFrequencyCount) {
            throw new AppException("訪問頻次過高,請稍候再試");
        }

2.使用lua腳本執(zhí)行,保證原子性。

腳本updateStore.lua

--- 獲取key
local key = KEYS[1]
--- 獲取參數(shù):incr、decr
local action = ARGV[1]
--- 如果key存在,再執(zhí)行增加或減少的操作
if redis.call('exists', key) == 1 
then redis.call(action, key)
    return true
end 
return false

配置LuaConfiguration.java

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;

@Configuration
public class LuaConfiguration {
    @Bean(name = "update")
    public DefaultRedisScript<Boolean> redisScript() {
        DefaultRedisScript<Boolean> redisScript = new DefaultRedisScript<>();
        redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("luascript/updateStore.lua")));
        redisScript.setResultType(Boolean.class);
        return redisScript;
    }
}

使用方法:

    @Resource(name = "update")
    private DefaultRedisScript<Boolean> redisScript;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
	// 執(zhí)行腳本并傳參
	Boolean result = stringRedisTemplate.execute(redisScript, Arrays.asList(stockPrefix.getPrefix() + key), "incr");

到此這篇關(guān)于Redis增減庫存避坑的實現(xiàn)的文章就介紹到這了,更多相關(guān)Redis增減庫存內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

  • 在ssm項目中使用redis緩存查詢數(shù)據(jù)的方法

    在ssm項目中使用redis緩存查詢數(shù)據(jù)的方法

    本文主要簡單的使用Java代碼進行redis緩存,即在查詢的時候先在service層從redis緩存中獲取數(shù)據(jù)。如果大家對在ssm項目中使用redis緩存查詢數(shù)據(jù)的相關(guān)知識感興趣的朋友跟隨腳本之家小編一起看看吧
    2018-03-03
  • 了解Redis常見應(yīng)用場景

    了解Redis常見應(yīng)用場景

    Redis是一個key-value存儲系統(tǒng),現(xiàn)在在各種系統(tǒng)中的使用越來越多,大部分情況下是因為其高性能的特性,被當(dāng)做緩存使用,這里介紹下Redis經(jīng)常遇到的使用場景
    2021-06-06
  • Redis實現(xiàn)鎖續(xù)期的項目實踐

    Redis實現(xiàn)鎖續(xù)期的項目實踐

    本文介紹了使用Redis實現(xiàn)分布式鎖的續(xù)期,包括使用Lua腳本、Redlock算法和Redisson客戶端等方法,具有一定的參考價值,感興趣的可以了解一下
    2024-12-12
  • Windows環(huán)境部署Redis集群

    Windows環(huán)境部署Redis集群

    這篇文章主要為大家詳細(xì)介紹了Windows環(huán)境部署Redis集群的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • 解決redis啟動的警告日志問題

    解決redis啟動的警告日志問題

    這篇文章主要介紹了解決redis啟動的警告日志問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • Jackson2JsonRedisSerializer和GenericJackson2JsonRedisSerializer區(qū)別

    Jackson2JsonRedisSerializer和GenericJackson2JsonRedisSerializ

    本文主要介紹了Jackson2JsonRedisSerializer和GenericJackson2JsonRedisSerializer區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • SpringBoot整合Redis實現(xiàn)序列化存儲Java對象的操作方法

    SpringBoot整合Redis實現(xiàn)序列化存儲Java對象的操作方法

    這篇文章主要介紹了SpringBoot整合Redis實現(xiàn)序列化存儲Java對象,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-03-03
  • Redis高可用集群redis-cluster詳解

    Redis高可用集群redis-cluster詳解

    redis?cluster?是redis官方提供的分布式解決方案,在3.0版本后推出的,有效地解決了redis分布式的需求,當(dāng)一個redis節(jié)點掛了可以快速的切換到另一個節(jié)點,對redis-cluster高可用集群相關(guān)知識感興趣的朋友一起看看吧
    2022-03-03
  • K8S redis 部署的項目實踐

    K8S redis 部署的項目實踐

    本文主要介紹了K8S redis 部署的項目實踐,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-05-05
  • Redis中群集三種模式的實現(xiàn)

    Redis中群集三種模式的實現(xiàn)

    Redis群集有三種模式,分別是主從同步/復(fù)制、哨兵模式、Cluster,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-11-11

最新評論

自贡市| 行唐县| 长汀县| 永善县| 北川| 当涂县| 兴宁市| 出国| 思南县| 望谟县| 霞浦县| 南阳市| 治县。| 松溪县| 怀柔区| 蓬安县| 兰考县| 大安市| 昭通市| 黄冈市| 澎湖县| 广汉市| 托克逊县| 陕西省| 惠州市| 溧水县| 马关县| 永丰县| 宁陕县| 诸暨市| 类乌齐县| 罗田县| 遵义市| 依兰县| 荣昌县| 呼和浩特市| 清流县| 越西县| 巨鹿县| 长沙县| 萨嘎县|