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

Redis解決秒殺微服務(wù)搶購代金券超賣和同一個(gè)用戶多次搶購

 更新時(shí)間:2025年09月21日 10:27:11   作者:共飲一杯無  
本文介紹了如何用Redis和Redisson分布式鎖解決秒殺中的超賣和同一用戶重復(fù)搶購問題,通過Lua腳本保證操作原子性,最終實(shí)現(xiàn)庫存和訂單的準(zhǔn)確控制,感興趣的可以了解一下

之前的博客,我通過 傳統(tǒng)的數(shù)據(jù)庫方式實(shí)現(xiàn)秒殺按照正常邏輯來走,通過壓力測試發(fā)現(xiàn)會(huì)有超賣合同一用戶可以多次搶購?fù)淮鹑膯栴}。本文我將講述通過redis來解決超賣和同一用戶多次搶購問題。

超賣和同一用戶多次搶購問題分析

    /**
     * 搶購代金券
     *
     * @param voucherId   代金券 ID
     * @param accessToken 登錄token
     * @Para path 訪問路徑
     */
    public ResultInfo doSeckill(Integer voucherId, String accessToken, String path) {
        // 基本參數(shù)校驗(yàn)
        AssertUtil.isTrue(voucherId == null || voucherId < 0, "請(qǐng)選擇需要搶購的代金券");
        AssertUtil.isNotEmpty(accessToken, "請(qǐng)登錄");
        // 判斷此代金券是否加入搶購
        SeckillVouchers seckillVouchers = seckillVouchersMapper.selectVoucher(voucherId);
        AssertUtil.isTrue(seckillVouchers == null, "該代金券并未有搶購活動(dòng)");
        // 判斷是否有效
        AssertUtil.isTrue(seckillVouchers.getIsValid() == 0, "該活動(dòng)已結(jié)束");
        // 判斷是否開始、結(jié)束
        Date now = new Date();
        AssertUtil.isTrue(now.before(seckillVouchers.getStartTime()), "該搶購還未開始");
        AssertUtil.isTrue(now.after(seckillVouchers.getEndTime()), "該搶購已結(jié)束");
        // 判斷是否賣完
        AssertUtil.isTrue(seckillVouchers.getAmount() < 1, "該券已經(jīng)賣完了");
        // 獲取登錄用戶信息
        String url = oauthServerName + "user/me?access_token={accessToken}";
        ResultInfo resultInfo = restTemplate.getForObject(url, ResultInfo.class, accessToken);
        if (resultInfo.getCode() != ApiConstant.SUCCESS_CODE) {
            resultInfo.setPath(path);
            return resultInfo;
        }
        // 這里的data是一個(gè)LinkedHashMap,SignInDinerInfo
        SignInDinerInfo dinerInfo = BeanUtil.fillBeanWithMap((LinkedHashMap) resultInfo.getData(),
                new SignInDinerInfo(), false);
        // 判斷登錄用戶是否已搶到(一個(gè)用戶針對(duì)這次活動(dòng)只能買一次)
        VoucherOrders order = voucherOrdersMapper.findDinerOrder(dinerInfo.getId(),
                seckillVouchers.getId());
        AssertUtil.isTrue(order != null, "該用戶已搶到該代金券,無需再搶");
        // 扣庫存
        int count = seckillVouchersMapper.stockDecrease(seckillVouchers.getId());
        AssertUtil.isTrue(count == 0, "該券已經(jīng)賣完了");
        // 下單
        VoucherOrders voucherOrders = new VoucherOrders();
        voucherOrders.setFkDinerId(dinerInfo.getId());
        voucherOrders.setFkSeckillId(seckillVouchers.getId());
        voucherOrders.setFkVoucherId(seckillVouchers.getFkVoucherId());
        String orderNo = IdUtil.getSnowflake(1, 1).nextIdStr();
        voucherOrders.setOrderNo(orderNo);
        voucherOrders.setOrderType(1);
        voucherOrders.setStatus(0);
        count = voucherOrdersMapper.save(voucherOrders);
        AssertUtil.isTrue(count == 0, "用戶搶購失敗");

        return ResultInfoUtil.buildSuccess(path, "搶購成功");
    }

高并發(fā)環(huán)境下會(huì)導(dǎo)致上圖的判斷出現(xiàn)錯(cuò)誤。在高并發(fā)環(huán)境下,會(huì)有多個(gè)線程拿到的庫存值都大于0,實(shí)際的繼續(xù)往下執(zhí)行的線程會(huì)高于實(shí)際的庫存值,繼續(xù)執(zhí)行會(huì)導(dǎo)致賣出的訂單量超過庫存本身的數(shù)量,導(dǎo)致庫存超賣。

同理同一用戶多次發(fā)起,同時(shí)到達(dá)這一步也會(huì)錯(cuò)判,在還沒有獲取到最新的存儲(chǔ)結(jié)果時(shí),都會(huì)判定成是未搶購過,導(dǎo)致同一用戶可以重復(fù)搶購問題。

解決庫存超賣問題

添加相關(guān)枚舉

在redis鍵的枚舉類中添加如下枚舉:

分布式鎖的key來約束同一用戶只能搶購一次。

添加RedisTemplate配置類

/**
 * RedisTemplate配置類
 * @author zjq
 */
@Configuration
public class RedisTemplateConfiguration {

    /**
     * redisTemplate 序列化使用的jdkSerializeable, 存儲(chǔ)二進(jìn)制字節(jié)碼, 所以自定義序列化類
     *
     * @param redisConnectionFactory
     * @return
     */
    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        // 使用Jackson2JsonRedisSerialize 替換默認(rèn)序列化
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        // 設(shè)置key和value的序列化規(guī)則
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setKeySerializer(new StringRedisSerializer());

        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);

        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    @Bean
    public DefaultRedisScript<Long> stockScript() {
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
        //放在和application.yml 同層目錄下
        redisScript.setLocation(new ClassPathResource("stock.lua"));
        redisScript.setResultType(Long.class);
        return redisScript;
    }

}

改造原先添加代金券邏輯

原先添加代金券的邏輯如下:

現(xiàn)在需要把跟數(shù)據(jù)庫交互的部分改成和redis交互,改造后代碼如下:

    	// 采用 Redis 實(shí)現(xiàn)
        String key = RedisKeyConstant.seckill_vouchers.getKey() +
                seckillVouchers.getFkVoucherId();
        // 驗(yàn)證 Redis 中是否已經(jīng)存在該券的秒殺活動(dòng)
        Map<String, Object> map = redisTemplate.opsForHash().entries(key);
        AssertUtil.isTrue(!map.isEmpty() && (int) map.get("amount") > 0, "該券已經(jīng)擁有了搶購活動(dòng)");

        // 插入 Redis
        seckillVouchers.setIsValid(1);
        seckillVouchers.setCreateDate(now);
        seckillVouchers.setUpdateDate(now);
        redisTemplate.opsForHash().putAll(key, BeanUtil.beanToMap(seckillVouchers));

執(zhí)行測試,新建秒殺代金券活動(dòng)存儲(chǔ)到Redis中:

可以看到數(shù)據(jù)已經(jīng)存儲(chǔ)到redis中。

改造下單邏輯

調(diào)整數(shù)據(jù)庫相關(guān)為redis

原先關(guān)系型數(shù)據(jù)庫下單邏輯:

    /**
     * 搶購代金券
     *
     * @param voucherId   代金券 ID
     * @param accessToken 登錄token
     * @Para path 訪問路徑
     */
    public ResultInfo doSeckill(Integer voucherId, String accessToken, String path) {
        // 基本參數(shù)校驗(yàn)
        AssertUtil.isTrue(voucherId == null || voucherId < 0, "請(qǐng)選擇需要搶購的代金券");
        AssertUtil.isNotEmpty(accessToken, "請(qǐng)登錄");
        // 判斷此代金券是否加入搶購
        SeckillVouchers seckillVouchers = seckillVouchersMapper.selectVoucher(voucherId);
        AssertUtil.isTrue(seckillVouchers == null, "該代金券并未有搶購活動(dòng)");
        // 判斷是否有效
        AssertUtil.isTrue(seckillVouchers.getIsValid() == 0, "該活動(dòng)已結(jié)束");
        // 判斷是否開始、結(jié)束
        Date now = new Date();
        AssertUtil.isTrue(now.before(seckillVouchers.getStartTime()), "該搶購還未開始");
        AssertUtil.isTrue(now.after(seckillVouchers.getEndTime()), "該搶購已結(jié)束");
        // 判斷是否賣完
        AssertUtil.isTrue(seckillVouchers.getAmount() < 1, "該券已經(jīng)賣完了");
        // 獲取登錄用戶信息
        String url = oauthServerName + "user/me?access_token={accessToken}";
        ResultInfo resultInfo = restTemplate.getForObject(url, ResultInfo.class, accessToken);
        if (resultInfo.getCode() != ApiConstant.SUCCESS_CODE) {
            resultInfo.setPath(path);
            return resultInfo;
        }
        // 這里的data是一個(gè)LinkedHashMap,SignInDinerInfo
        SignInDinerInfo dinerInfo = BeanUtil.fillBeanWithMap((LinkedHashMap) resultInfo.getData(),
                new SignInDinerInfo(), false);
        // 判斷登錄用戶是否已搶到(一個(gè)用戶針對(duì)這次活動(dòng)只能買一次)
        VoucherOrders order = voucherOrdersMapper.findDinerOrder(dinerInfo.getId(),
                seckillVouchers.getId());
        AssertUtil.isTrue(order != null, "該用戶已搶到該代金券,無需再搶");
        // 扣庫存
        int count = seckillVouchersMapper.stockDecrease(seckillVouchers.getId());
        AssertUtil.isTrue(count == 0, "該券已經(jīng)賣完了");
        // 下單
        VoucherOrders voucherOrders = new VoucherOrders();
        voucherOrders.setFkDinerId(dinerInfo.getId());
        voucherOrders.setFkSeckillId(seckillVouchers.getId());
        voucherOrders.setFkVoucherId(seckillVouchers.getFkVoucherId());
        String orderNo = IdUtil.getSnowflake(1, 1).nextIdStr();
        voucherOrders.setOrderNo(orderNo);
        voucherOrders.setOrderType(1);
        voucherOrders.setStatus(0);
        count = voucherOrdersMapper.save(voucherOrders);
        AssertUtil.isTrue(count == 0, "用戶搶購失敗");

        return ResultInfoUtil.buildSuccess(path, "搶購成功");
    }

查詢、扣庫存和下單邏輯調(diào)整成Redis:

    	// 扣庫存 redis沒有自減方法,數(shù)值傳負(fù)數(shù)表示自減
        long count = redisTemplate.opsForHash().increment(key, "amount", -1);
        AssertUtil.isTrue(count <= 0, "該券已經(jīng)賣完了");

訂單信息還是保存到數(shù)據(jù)庫中

        // 下單
        VoucherOrders voucherOrders = new VoucherOrders();
        voucherOrders.setFkDinerId(dinerInfo.getId());
        //redis中不需要維護(hù)該外鍵信息
//        voucherOrders.setFkSeckillId(seckillVouchers.getId());
        voucherOrders.setFkVoucherId(seckillVouchers.getFkVoucherId());
        String orderNo = IdUtil.getSnowflake(1, 1).nextIdStr();
        voucherOrders.setOrderNo(orderNo);
        voucherOrders.setOrderType(1);
        voucherOrders.setStatus(0);
        count = voucherOrdersMapper.save(voucherOrders);

JMeter發(fā)起3000個(gè)線程,2000個(gè)用戶并發(fā)請(qǐng)求,查看庫存情況,目前還是超賣的:

訂單的數(shù)量是正確的:

因?yàn)檫@一步判定是單線程的

long count = redisTemplate.opsForHash().increment(key, "amount", -1);
AssertUtil.isTrue(count <= 0, "該券已經(jīng)賣完了");

是不是先下單然后再扣庫存就可以了?當(dāng)然不行,如果上面位置調(diào)整下會(huì)導(dǎo)致庫存數(shù)量不對(duì),訂單數(shù)量也不對(duì)??????。
我們繼續(xù)在先下單后扣庫存的方法上添加一個(gè)事務(wù):@Transactional(rollbackFor = Exception.class)。
執(zhí)行發(fā)現(xiàn)訂單數(shù)量正常了,庫存還是負(fù)數(shù):

為什么會(huì)有這個(gè)問題呢,因?yàn)?code>redisTemplate.opsForHash().increment(key, "amount", -1)這一步操作在redis中實(shí)際執(zhí)行的是先查詢?cè)贉p少的操作,在高并發(fā)場景下會(huì)有問題。我們需要保證這兩步的原子性。

Redis + Lua 解決超賣問題

在yml配置文件同級(jí)目錄添加lua腳本,腳本內(nèi)容如下:

if (redis.call('hexists', KEYS[1], KEYS[2]) == 1) then
	local stock = tonumber(redis.call('hget', KEYS[1], KEYS[2]));
	if (stock > 0) then
	   redis.call('hincrby', KEYS[1], KEYS[2], -1);
	   return stock;
	end;
    return 0;
end;

在RedisTemplate配置類中添加如下配置bean并注入lua腳本:

    @Bean
    public DefaultRedisScript<Long> stockScript() {
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
        //放在和application.yml 同層目錄下
        redisScript.setLocation(new ClassPathResource("stock.lua"));
        redisScript.setResultType(Long.class);
        return redisScript;
    }

扣庫存邏輯調(diào)整如下:

            	// 采用 Redis + Lua 解決超賣問題
                // 扣庫存
                List<String> keys = new ArrayList<>();
                keys.add(key);
                keys.add("amount");
                Long amount = (Long) redisTemplate.execute(defaultRedisScript, keys);
                AssertUtil.isTrue(amount == null || amount < 1, "該券已經(jīng)賣完了");

重置數(shù)據(jù)后執(zhí)行JMeter執(zhí)行5000個(gè)線程,兩千個(gè)用戶并發(fā)下單測試,結(jié)果如下:

庫存0,訂單100,超賣問題解決。

JMeter的結(jié)果值有中文亂碼,進(jìn)入JMeter安裝位置,調(diào)整jmeter.properties文件中的sampleresult.default.encoding為UTF-8。重啟JMeter再測試不再亂碼。

解決同一用戶多次搶購問題

問題描述

用JMeter測試同一用戶并發(fā)搶購:

查看數(shù)據(jù)庫發(fā)現(xiàn)同一用戶下單了多次:

Redisson 分布式鎖解決同一用戶多次下單

什么是Redisson

上圖就是redission官方網(wǎng)站首頁。
首頁可以看出來,Redisson可以實(shí)現(xiàn)很多東西,在Redis的基礎(chǔ)上,Redisson做了超多的封裝,我們看一下,例如說
Spring Cache,TomcatSession,Spring Session,可排序的Set,還有呢Sortedsort,下面還有各種隊(duì)列,包括這種雙端
隊(duì)列,還有map,這些是數(shù)據(jù)結(jié)構(gòu),下面就是各種鎖,讀寫鎖,這里面的鎖還包含,可重入鎖,還有CountDownLantch,這個(gè)是在多線程的時(shí)候使用的,比如說我啟動(dòng)很多個(gè)線程,去執(zhí)行某個(gè)任務(wù),然后把任務(wù)進(jìn)行切分,都完成之后有一個(gè)等待,等待所有線程都達(dá)到這里之后,在一起往下走,把異步再變成同步,下邊是一些線程池,還有訂閱的各種功能,ScheduleService來做調(diào)度的一個(gè)任務(wù),所以Redisson是非常強(qiáng)大的,然后我們?cè)谟疑辖怯幸粋€(gè)documentation,我們可以打開它,Redisson官方也提供了中文文檔:https://github.com/redisson/redisson/wiki/目錄

問題解決

同一用戶可以多次搶購本質(zhì)上是一個(gè)用戶在搶購的某個(gè)商品的時(shí)候沒有加鎖,導(dǎo)致同一用戶的多個(gè)線程同時(shí)進(jìn)入搶購,接下來通過Redisson分布式鎖來解決同一用戶多次下單的問題。
鎖的對(duì)象為用戶id和代金券活動(dòng)id,表示同一用戶只能搶購一次某活動(dòng)。改造后代碼如下:

    /**
     * 搶購代金券
     *
     * @param voucherId   代金券 ID
     * @param accessToken 登錄token
     * @Para path 訪問路徑
     */
    @Transactional(rollbackFor = Exception.class)
    public ResultInfo doSeckill(Integer voucherId, String accessToken, String path) {
        // 基本參數(shù)校驗(yàn)
        AssertUtil.isTrue(voucherId == null || voucherId < 0, "請(qǐng)選擇需要搶購的代金券");
        AssertUtil.isNotEmpty(accessToken, "請(qǐng)登錄");

        // 采用 Redis
        String key = RedisKeyConstant.seckill_vouchers.getKey() + voucherId;
        Map<String, Object> map = redisTemplate.opsForHash().entries(key);
        SeckillVouchers seckillVouchers = BeanUtil.mapToBean(map, SeckillVouchers.class, true, null);
        // 判斷是否開始、結(jié)束
        Date now = new Date();
        AssertUtil.isTrue(now.before(seckillVouchers.getStartTime()), "該搶購還未開始");
        AssertUtil.isTrue(now.after(seckillVouchers.getEndTime()), "該搶購已結(jié)束");
        // 判斷是否賣完
        AssertUtil.isTrue(seckillVouchers.getAmount() < 1, "該券已經(jīng)賣完了");
        // 獲取登錄用戶信息
        String url = oauthServerName + "user/me?access_token={accessToken}";
        ResultInfo resultInfo = restTemplate.getForObject(url, ResultInfo.class, accessToken);
        if (resultInfo.getCode() != ApiConstant.SUCCESS_CODE) {
            resultInfo.setPath(path);
            return resultInfo;
        }
        // 這里的data是一個(gè)LinkedHashMap,SignInDinerInfo
        SignInDinerInfo dinerInfo = BeanUtil.fillBeanWithMap((LinkedHashMap) resultInfo.getData(),
                new SignInDinerInfo(), false);
        // 判斷登錄用戶是否已搶到(一個(gè)用戶針對(duì)這次活動(dòng)只能買一次)
        VoucherOrders order = voucherOrdersMapper.findDinerOrder(dinerInfo.getId(),
                seckillVouchers.getId());
        AssertUtil.isTrue(order != null, "該用戶已搶到該代金券,無需再搶");

        // 使用 Redis 鎖一個(gè)賬號(hào)只能購買一次
        String lockName = RedisKeyConstant.lock_key.getKey()
                + dinerInfo.getId() + ":" + voucherId;
        long expireTime = seckillVouchers.getEndTime().getTime() - now.getTime();

        // Redisson 分布式鎖
        RLock lock = redissonClient.getLock(lockName);
        try {

            // Redisson 分布式鎖處理
            boolean isLocked = lock.tryLock(expireTime, TimeUnit.MILLISECONDS);
            if (isLocked) {
                // 下單
                VoucherOrders voucherOrders = new VoucherOrders();
                voucherOrders.setFkDinerId(dinerInfo.getId());
                //redis中不需要維護(hù)該外鍵信息
                //        voucherOrders.setFkSeckillId(seckillVouchers.getId());
                voucherOrders.setFkVoucherId(seckillVouchers.getFkVoucherId());
                String orderNo = IdUtil.getSnowflake(1, 1).nextIdStr();
                voucherOrders.setOrderNo(orderNo);
                voucherOrders.setOrderType(1);
                voucherOrders.setStatus(0);
                long count = voucherOrdersMapper.save(voucherOrders);
                AssertUtil.isTrue(count == 0, "用戶搶購失敗");

                // 采用 Redis + Lua 解決超賣問題
                // 扣庫存
                List<String> keys = new ArrayList<>();
                keys.add(key);
                keys.add("amount");
                Long amount = (Long) redisTemplate.execute(defaultRedisScript, keys);
                AssertUtil.isTrue(amount == null || amount < 1, "該券已經(jīng)賣完了");
            }
        } catch (Exception e) {
            // 手動(dòng)回滾事務(wù)
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

            // Redisson 解鎖
            lock.unlock();
            if (e instanceof ParameterException) {
                return ResultInfoUtil.buildError(0, "該券已經(jīng)賣完了", path);
            }
        }

        return ResultInfoUtil.buildSuccess(path, "搶購成功");
    }

JMeter測試驗(yàn)證,同一用戶并發(fā)請(qǐng)求某一活動(dòng),只能下單一次:

庫存剩99,訂單1條,完美。

到此這篇關(guān)于Redis解決秒殺微服務(wù)搶購代金券超賣和同一個(gè)用戶多次搶購的文章就介紹到這了,更多相關(guān)Redis超賣和同一個(gè)用戶多次搶購內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Redis通過scan查找不過期的 key(方法詳解)

    Redis通過scan查找不過期的 key(方法詳解)

    SCAN 命令是一個(gè)基于游標(biāo)的迭代器,每次被調(diào)用之后, 都會(huì)向用戶返回一個(gè)新的游標(biāo), 用戶在下次迭代時(shí)需要使用這個(gè)新游標(biāo)作為 SCAN 命令的游標(biāo)參數(shù), 以此來延續(xù)之前的迭代過程,對(duì)Redis scan 查找 key相關(guān)知識(shí)感興趣的朋友一起看看吧
    2021-08-08
  • 淺談redis在項(xiàng)目中的應(yīng)用

    淺談redis在項(xiàng)目中的應(yīng)用

    下面小編就為大家?guī)硪黄獪\談redis在項(xiàng)目中的應(yīng)用。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2016-12-12
  • 使用Redis實(shí)現(xiàn)分布式鎖的方法

    使用Redis實(shí)現(xiàn)分布式鎖的方法

    為了保證我們線上服務(wù)的并發(fā)性和安全性,目前我們的服務(wù)一般拋棄了單體應(yīng)用,采用的都是擴(kuò)展性很強(qiáng)的分布式架構(gòu),這篇文章主要介紹了使用Redis實(shí)現(xiàn)分布式鎖的方法,需要的朋友可以參考下
    2022-06-06
  • 一文弄懂Redis 線程模型

    一文弄懂Redis 線程模型

    使用Redis 時(shí),幾乎不存在 CPU 成為瓶頸的情況, Redis 主要受限于內(nèi)存和網(wǎng)絡(luò) 使用了單線程后,可維護(hù)性高,感興趣的可以了解一下
    2024-02-02
  • Redisson分布式鎖之加解鎖詳解

    Redisson分布式鎖之加解鎖詳解

    這篇文章主要為大家介紹了Redisson分布式鎖加解鎖的詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • 淺析PHP分布式中Redis實(shí)現(xiàn)Session的方法

    淺析PHP分布式中Redis實(shí)現(xiàn)Session的方法

    這篇文章主要介紹了PHP分布式中Redis實(shí)現(xiàn)Session的方法,文中詳細(xì)介紹了兩種方法的使用方法,并給出了測試的示例代碼,有需要的朋友可以參考借鑒,下面來一起看看吧,
    2016-12-12
  • 使用Docker部署Redis并配置持久化與密碼保護(hù)的詳細(xì)步驟

    使用Docker部署Redis并配置持久化與密碼保護(hù)的詳細(xì)步驟

    本文將詳細(xì)介紹如何使用 Docker 部署 Redis,并通過 redis.conf 配置文件實(shí)現(xiàn)數(shù)據(jù)持久化和密碼保護(hù),適合在生產(chǎn)環(huán)境中使用,文章通過代碼示例講解的非常詳細(xì),需要的朋友可以參考下
    2025-03-03
  • redis中l(wèi)ua腳本使用教程

    redis中l(wèi)ua腳本使用教程

    在使用redis的過程中,發(fā)現(xiàn)有些時(shí)候需要原子性去操作redis命令,而redis的lua腳本正好可以實(shí)現(xiàn)這一功能。這篇文章主要介紹了redis中l(wèi)ua腳本的簡單使用,需要的朋友可以參考下
    2021-10-10
  • RabbitMQ+redis+Redisson分布式鎖+seata實(shí)現(xiàn)訂單服務(wù)的流程分析

    RabbitMQ+redis+Redisson分布式鎖+seata實(shí)現(xiàn)訂單服務(wù)的流程分析

    訂單服務(wù)涉及許多方面,分布式事務(wù),分布式鎖,例如訂單超時(shí)未支付要取消訂單,訂單如何防止重復(fù)提交,如何防止超賣、這里都會(huì)使用到,這篇文章主要介紹了RabbitMQ+redis+Redisson分布式鎖+seata實(shí)現(xiàn)訂單服務(wù)的流程分析,需要的朋友可以參考下
    2024-07-07
  • 了解redis中RDB結(jié)構(gòu)_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    了解redis中RDB結(jié)構(gòu)_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    這篇文章主要為大家詳細(xì)介紹了redis中RDB結(jié)構(gòu),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-08-08

最新評(píng)論

分宜县| 平遥县| 新丰县| 札达县| 济宁市| 新昌县| 车致| 黔江区| 海安县| 景泰县| 麻江县| 简阳市| 阳城县| 德昌县| 嘉定区| 连江县| 柳河县| 石首市| 合作市| 托里县| 汾阳市| 平邑县| 洪雅县| 丘北县| 房产| 瓦房店市| 潞西市| 健康| 武城县| 田林县| 韩城市| 临西县| 东海县| 林甸县| 竹溪县| 枣阳市| 武陟县| 蓝山县| 汝阳县| 怀集县| 沾益县|