亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

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

超賣(mài)和同一用戶多次搶購(gòu)問(wèn)題分析

    /**
     * 搶購(gòu)代金券
     *
     * @param voucherId   代金券 ID
     * @param accessToken 登錄token
     * @Para path 訪問(wèn)路徑
     */
    public ResultInfo doSeckill(Integer voucherId, String accessToken, String path) {
        // 基本參數(shù)校驗(yàn)
        AssertUtil.isTrue(voucherId == null || voucherId < 0, "請(qǐng)選擇需要搶購(gòu)的代金券");
        AssertUtil.isNotEmpty(accessToken, "請(qǐng)登錄");
        // 判斷此代金券是否加入搶購(gòu)
        SeckillVouchers seckillVouchers = seckillVouchersMapper.selectVoucher(voucherId);
        AssertUtil.isTrue(seckillVouchers == null, "該代金券并未有搶購(gòu)活動(dòng)");
        // 判斷是否有效
        AssertUtil.isTrue(seckillVouchers.getIsValid() == 0, "該活動(dòng)已結(jié)束");
        // 判斷是否開(kāi)始、結(jié)束
        Date now = new Date();
        AssertUtil.isTrue(now.before(seckillVouchers.getStartTime()), "該搶購(gòu)還未開(kāi)始");
        AssertUtil.isTrue(now.after(seckillVouchers.getEndTime()), "該搶購(gòu)已結(jié)束");
        // 判斷是否賣(mài)完
        AssertUtil.isTrue(seckillVouchers.getAmount() < 1, "該券已經(jīng)賣(mài)完了");
        // 獲取登錄用戶信息
        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)只能買(mǎi)一次)
        VoucherOrders order = voucherOrdersMapper.findDinerOrder(dinerInfo.getId(),
                seckillVouchers.getId());
        AssertUtil.isTrue(order != null, "該用戶已搶到該代金券,無(wú)需再搶");
        // 扣庫(kù)存
        int count = seckillVouchersMapper.stockDecrease(seckillVouchers.getId());
        AssertUtil.isTrue(count == 0, "該券已經(jīng)賣(mài)完了");
        // 下單
        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, "用戶搶購(gòu)失敗");

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

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

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

解決庫(kù)存超賣(mài)問(wèn)題

添加相關(guān)枚舉

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

分布式鎖的key來(lái)約束同一用戶只能搶購(gòu)一次。

添加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ù)庫(kù)交互的部分改成和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)擁有了搶購(gòu)活動(dòng)");

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

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

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

改造下單邏輯

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

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

    /**
     * 搶購(gòu)代金券
     *
     * @param voucherId   代金券 ID
     * @param accessToken 登錄token
     * @Para path 訪問(wèn)路徑
     */
    public ResultInfo doSeckill(Integer voucherId, String accessToken, String path) {
        // 基本參數(shù)校驗(yàn)
        AssertUtil.isTrue(voucherId == null || voucherId < 0, "請(qǐng)選擇需要搶購(gòu)的代金券");
        AssertUtil.isNotEmpty(accessToken, "請(qǐng)登錄");
        // 判斷此代金券是否加入搶購(gòu)
        SeckillVouchers seckillVouchers = seckillVouchersMapper.selectVoucher(voucherId);
        AssertUtil.isTrue(seckillVouchers == null, "該代金券并未有搶購(gòu)活動(dòng)");
        // 判斷是否有效
        AssertUtil.isTrue(seckillVouchers.getIsValid() == 0, "該活動(dòng)已結(jié)束");
        // 判斷是否開(kāi)始、結(jié)束
        Date now = new Date();
        AssertUtil.isTrue(now.before(seckillVouchers.getStartTime()), "該搶購(gòu)還未開(kāi)始");
        AssertUtil.isTrue(now.after(seckillVouchers.getEndTime()), "該搶購(gòu)已結(jié)束");
        // 判斷是否賣(mài)完
        AssertUtil.isTrue(seckillVouchers.getAmount() < 1, "該券已經(jīng)賣(mài)完了");
        // 獲取登錄用戶信息
        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)只能買(mǎi)一次)
        VoucherOrders order = voucherOrdersMapper.findDinerOrder(dinerInfo.getId(),
                seckillVouchers.getId());
        AssertUtil.isTrue(order != null, "該用戶已搶到該代金券,無(wú)需再搶");
        // 扣庫(kù)存
        int count = seckillVouchersMapper.stockDecrease(seckillVouchers.getId());
        AssertUtil.isTrue(count == 0, "該券已經(jīng)賣(mài)完了");
        // 下單
        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, "用戶搶購(gòu)失敗");

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

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

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

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

        // 下單
        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)求,查看庫(kù)存情況,目前還是超賣(mài)的:

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

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

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

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

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

Redis + Lua 解決超賣(mài)問(wèn)題

在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;
    }

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

            	// 采用 Redis + Lua 解決超賣(mài)問(wèn)題
                // 扣庫(kù)存
                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)賣(mài)完了");

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

庫(kù)存0,訂單100,超賣(mài)問(wèn)題解決。

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

解決同一用戶多次搶購(gòu)問(wèn)題

問(wèn)題描述

用JMeter測(cè)試同一用戶并發(fā)搶購(gòu):

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

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

什么是Redisson

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

問(wèn)題解決

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

    /**
     * 搶購(gòu)代金券
     *
     * @param voucherId   代金券 ID
     * @param accessToken 登錄token
     * @Para path 訪問(wèn)路徑
     */
    @Transactional(rollbackFor = Exception.class)
    public ResultInfo doSeckill(Integer voucherId, String accessToken, String path) {
        // 基本參數(shù)校驗(yàn)
        AssertUtil.isTrue(voucherId == null || voucherId < 0, "請(qǐng)選擇需要搶購(gòu)的代金券");
        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);
        // 判斷是否開(kāi)始、結(jié)束
        Date now = new Date();
        AssertUtil.isTrue(now.before(seckillVouchers.getStartTime()), "該搶購(gòu)還未開(kāi)始");
        AssertUtil.isTrue(now.after(seckillVouchers.getEndTime()), "該搶購(gòu)已結(jié)束");
        // 判斷是否賣(mài)完
        AssertUtil.isTrue(seckillVouchers.getAmount() < 1, "該券已經(jīng)賣(mài)完了");
        // 獲取登錄用戶信息
        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)只能買(mǎi)一次)
        VoucherOrders order = voucherOrdersMapper.findDinerOrder(dinerInfo.getId(),
                seckillVouchers.getId());
        AssertUtil.isTrue(order != null, "該用戶已搶到該代金券,無(wú)需再搶");

        // 使用 Redis 鎖一個(gè)賬號(hào)只能購(gòu)買(mǎi)一次
        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, "用戶搶購(gòu)失敗");

                // 采用 Redis + Lua 解決超賣(mài)問(wèn)題
                // 扣庫(kù)存
                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)賣(mài)完了");
            }
        } catch (Exception e) {
            // 手動(dòng)回滾事務(wù)
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

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

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

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

庫(kù)存剩99,訂單1條,完美。

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

相關(guān)文章

  • Redis分布式鎖之紅鎖的實(shí)現(xiàn)

    Redis分布式鎖之紅鎖的實(shí)現(xiàn)

    本文主要介紹了Redis分布式鎖之紅鎖的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • Redis Sentinel的使用方法

    Redis Sentinel的使用方法

    這篇文章主要介紹了Redis Sentinel的使用方法,幫助大家更好的理解和學(xué)習(xí)使用Redis數(shù)據(jù)庫(kù),感興趣的朋友可以了解下
    2021-03-03
  • 解決Redis開(kāi)啟遠(yuǎn)程訪問(wèn)及密碼問(wèn)題

    解決Redis開(kāi)啟遠(yuǎn)程訪問(wèn)及密碼問(wèn)題

    這篇文章主要介紹了Redis開(kāi)啟遠(yuǎn)程訪問(wèn)及密碼的教程,文中給大家提到了Redis啟動(dòng)報(bào)錯(cuò)解決方法,需要的朋友可以參考下
    2019-10-10
  • Redisson實(shí)現(xiàn)分布式鎖、鎖續(xù)約的案例

    Redisson實(shí)現(xiàn)分布式鎖、鎖續(xù)約的案例

    這篇文章主要介紹了Redisson如何實(shí)現(xiàn)分布式鎖、鎖續(xù)約,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-03-03
  • Redis未授權(quán)訪問(wèn)配合SSH key文件利用詳解

    Redis未授權(quán)訪問(wèn)配合SSH key文件利用詳解

    這篇文章主要給大家介紹了關(guān)于Redis未授權(quán)訪問(wèn)配合SSH key文件利用的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-09-09
  • 關(guān)于redis Key淘汰策略的實(shí)現(xiàn)方法

    關(guān)于redis Key淘汰策略的實(shí)現(xiàn)方法

    下面小編就為大家?guī)?lái)一篇關(guān)于redis Key淘汰策略的實(shí)現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-03-03
  • Redis遍歷所有key的兩個(gè)命令(KEYS 和 SCAN)

    Redis遍歷所有key的兩個(gè)命令(KEYS 和 SCAN)

    這篇文章主要介紹了Redis遍歷所有key的兩個(gè)命令(KEYS 和 SCAN),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • Redis消息隊(duì)列實(shí)現(xiàn)異步秒殺功能

    Redis消息隊(duì)列實(shí)現(xiàn)異步秒殺功能

    在高并發(fā)場(chǎng)景下,為了提高秒殺業(yè)務(wù)的性能,可將部分工作交給 Redis 處理,并通過(guò)異步方式執(zhí)行,Redis 提供了多種數(shù)據(jù)結(jié)構(gòu)來(lái)實(shí)現(xiàn)消息隊(duì)列,總結(jié)三種,本文詳細(xì)介紹Redis消息隊(duì)列實(shí)現(xiàn)異步秒殺功能,感興趣的朋友一起看看吧
    2025-04-04
  • 詳解redis中的下載和安裝(最新推薦)

    詳解redis中的下載和安裝(最新推薦)

    本文詳細(xì)介紹了如何在Linux和Docker上安裝、配置、啟動(dòng)和關(guān)閉Redis,包括下載安裝包、解壓、編譯安裝、配置文件修改、前臺(tái)和后臺(tái)啟動(dòng)、關(guān)閉以及Docker容器化部署等步驟,感興趣的朋友一起看看吧
    2025-03-03
  • Redis進(jìn)行相關(guān)優(yōu)化詳解

    Redis進(jìn)行相關(guān)優(yōu)化詳解

    這篇文章主要介紹了Redis進(jìn)行相關(guān)優(yōu)化,Redis在項(xiàng)目中進(jìn)行廣泛使用,那么在日常的開(kāi)發(fā)過(guò)程中,我們?cè)谑褂肦edis的過(guò)程中需要注意那些呢?本文將從三個(gè)維度來(lái)講解如何進(jìn)行Redis的優(yōu)化
    2022-08-08

最新評(píng)論