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

Redis分布式鎖實例分析講解

 更新時間:2022年12月06日 16:05:13   作者:芝麻干  
分布式鎖是控制分布式系統(tǒng)不同進程共同訪問共享資源的一種鎖的實現(xiàn)。如果不同的系統(tǒng)或同一個系統(tǒng)的不同主機之間共享了某個臨界資源,往往需要互斥來防止彼此干擾,以保證一致性

1 一人一單并發(fā)安全問題

之前一人一單的業(yè)務使用的悲觀鎖,在分布式系統(tǒng)下,是無法生效的。

理想的情況下是這樣的:一個線程成功獲取互斥鎖,并對查詢訂單并創(chuàng)建訂單,其他線程無法干預。它的原理是會有一個鎖監(jiān)視器,來監(jiān)聽是誰獲得了鎖。

但是問題就出現(xiàn)在:

分布式系統(tǒng)下,有多個不同的JVM,不同的JVM的環(huán)境下,鎖監(jiān)聽器是有多個的,就會出現(xiàn)有的線程在別的線程已經(jīng)拿到鎖的情況下,仍然可以獲取的到鎖。

這個時候,普通的JVM中的鎖就已經(jīng)不管用了,就需要我們利用分布式鎖 。

2 分布式鎖的原理和實現(xiàn)

2.1 什么是分布式鎖

就是可以滿足分布式系統(tǒng)或集群模式下多進程可見并且互斥的鎖。

它的實現(xiàn)原理就是,不同的JVM環(huán)境,都來共用一個鎖監(jiān)視器。這樣就不會導致出現(xiàn)多個線程用多把鎖的情況了。

特點:

2.2 分布式鎖的實現(xiàn)

主要有三種實現(xiàn)方法,我們可以都來進行一個對比。

如下圖:

這里主要講基于Redis的分布式鎖的實現(xiàn) 。

實現(xiàn)Reids分布式鎖的方法主要就下面兩個步驟:

1. 獲取鎖

獲取鎖的方法已經(jīng)是老朋友了,就是使用Redis String類型方法中的setnx方法(互斥性)。但是,為了預防redis服務器宕機的問題,我們要給鎖設置一個超時時間,避免出現(xiàn)死鎖。(非阻塞)

所以,獲取鎖的方式可以使用如下代碼

SET lock thread1 nx ex 10

lock是鎖的key,thread1 是value,nx就是setnx方法,ex就是設置超時時間

2. 釋放鎖

釋放鎖就簡單了,刪除即可。

del lock

代碼實現(xiàn):

需求:定義一個接口,利用Redis實現(xiàn)分布式鎖的功能。

代碼如下:

接口代碼:

package com.hmdp.utils;
public interface ILock {
    /**
     * 嘗試獲取鎖
     * @param timeoutSec 鎖的持有時間,過期自動釋放
     * @return true代表獲取鎖成功,false代表獲取鎖失敗。
     */
    boolean tryLock(long timeoutSec);
    /**
     * 釋放鎖
     */
    void unlock();
}

接口實現(xiàn)類:

package com.hmdp.utils;
import org.springframework.data.redis.core.StringRedisTemplate;
import java.util.concurrent.TimeUnit;
/**
 * @Version 1.0
 */
public class SimpleRedisLock implements ILock {
    //Redis
    private StringRedisTemplate stringRedisTemplate;
    //業(yè)務名稱,也就是鎖的名稱
    private String name;
    public SimpleRedisLock(StringRedisTemplate stringRedisTemplate, String name) {
        this.stringRedisTemplate = stringRedisTemplate;
        this.name = name;
    }
    //key的前綴
    private static final String KEY_PREFIX = "lock:";
    @Override
    public boolean tryLock(long timeoutSec) {
        //獲取線程id,當作set的value
        long threadId = Thread.currentThread().getId();
        Boolean success = stringRedisTemplate.opsForValue()
                .setIfAbsent(KEY_PREFIX + name, threadId+"", timeoutSec, TimeUnit.SECONDS);
        return Boolean.TRUE.equals(success);
    }
    //釋放鎖
    @Override
    public void unlock() {
        //刪除key
        stringRedisTemplate.delete(KEY_PREFIX+name);
    }
}

業(yè)務層獲取鎖和釋放鎖(優(yōu)惠券秒殺業(yè)務修改)

package com.hmdp.service.impl;
import com.hmdp.dto.Result;
import com.hmdp.entity.SeckillVoucher;
import com.hmdp.entity.VoucherOrder;
import com.hmdp.mapper.VoucherOrderMapper;
import com.hmdp.service.ISeckillVoucherService;
import com.hmdp.service.IVoucherOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.utils.RedisIdWorker;
import com.hmdp.utils.SimpleRedisLock;
import com.hmdp.utils.UserHolder;
import org.springframework.aop.framework.AopContext;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.time.LocalDateTime;
/**
 * <p>
 *  服務實現(xiàn)類
 * </p>
 *
 */
@Service
public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService {
 
    @Resource
    private ISeckillVoucherService iSeckillVoucherService;
    @Resource
    private RedisIdWorker redisIdWorker;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Override
    public Result seckillVoucher(Long voucherId) {
        //1.獲取優(yōu)惠券信息
        SeckillVoucher voucher = iSeckillVoucherService.getById(voucherId);
        //2.判斷是否已經(jīng)開始
        if (voucher.getBeginTime().isAfter(LocalDateTime.now())){
            Result.fail("秒殺尚未開始!");
        }
        //3.判斷是否已經(jīng)結束
        if (voucher.getEndTime().isBefore(LocalDateTime.now())){
            Result.fail("秒殺已經(jīng)結束了!");
        }
        //4.判斷庫存是否充足
        if (voucher.getStock() < 1) {
            Result.fail("庫存不充足!");
        }
        //5.扣減庫存
        boolean success = iSeckillVoucherService.update()
                .setSql("stock = stock-1").eq("voucher_id",voucherId).gt("stock",0)
                .update();
        if (!success){
            Result.fail("庫存不充足!");
        }
        Long userId = UserHolder.getUser().getId();
        //1.創(chuàng)建鎖對象
        SimpleRedisLock lock = new SimpleRedisLock(stringRedisTemplate, "order:" + userId);
        //2.嘗試獲取鎖
        boolean isLock = lock.tryLock(1200);
        if (!isLock){
            //獲取鎖失敗
            return Result.fail("一個用戶只能下一單!");
        }
        try {
            IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();
            return proxy.createVoucherOrder(voucherId);
        } finally {
            //釋放鎖
            lock.unlock();
        }
    }
    @Transactional
    public Result createVoucherOrder(Long voucherId) {
        Long userId = UserHolder.getUser().getId();
        //6.根據(jù)優(yōu)惠券id和用戶id判斷訂單是否已經(jīng)存在
        //如果存在,則返回錯誤信息
        int count = query().eq("user_id", userId).eq("voucher_id", voucherId).count();
        if (count > 0) {
            return Result.fail("用戶已經(jīng)購買!");
        }
        //7. 創(chuàng)建訂單
        VoucherOrder voucherOrder = new VoucherOrder();
        //7.1添加訂單id
        Long orderId = redisIdWorker.nextId("order");
        voucherOrder.setId(orderId);
        //7.2添加用戶id
        voucherOrder.setUserId(userId);
        //7.3添加優(yōu)惠券id
        voucherOrder.setVoucherId(voucherId);
        save(voucherOrder);
        //8.返回訂單id
        return Result.ok(orderId);
    }
}

到此這篇關于Redis分布式鎖實例分析講解的文章就介紹到這了,更多相關Redis分布式鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Redis持久化方式之RDB和AOF的原理及優(yōu)缺點

    Redis持久化方式之RDB和AOF的原理及優(yōu)缺點

    在Redis中,數(shù)據(jù)可以分為兩類,即內(nèi)存數(shù)據(jù)和磁盤數(shù)據(jù),Redis?提供了兩種不同的持久化方式,其中?RDB?是快照備份機制,AOF?則是追加寫操作機制,本文將詳細給大家介紹Redis?持久化方式RDB和AOF的原理及優(yōu)缺點,感興趣的同學可以跟著小編一起來學習
    2023-06-06
  • 微服務Spring Boot 整合 Redis 實現(xiàn)好友關注功能

    微服務Spring Boot 整合 Redis 實現(xiàn)好友關注功能

    這篇文章主要介紹了微服務Spring Boot 整合 Redis 實現(xiàn) 好友關注,本文結合示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-12-12
  • Redis優(yōu)惠券秒殺解決方案

    Redis優(yōu)惠券秒殺解決方案

    這篇文章主要介紹了Redis解決優(yōu)惠券秒殺應用案例,本文先講了搶購問題,指出其中會出現(xiàn)的多線程問題,提出解決方案采用悲觀鎖和樂觀鎖兩種方式進行實現(xiàn),然后發(fā)現(xiàn)在搶購過程中容易出現(xiàn)一人多單現(xiàn)象,需要的朋友可以參考下
    2022-12-12
  • Redis定時任務原理的實現(xiàn)

    Redis定時任務原理的實現(xiàn)

    本文主要是基于?redis?6.2?源碼進行分析定時事件的數(shù)據(jù)結構和常見操作,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • 利用redis實現(xiàn)聊天記錄轉存功能的全過程

    利用redis實現(xiàn)聊天記錄轉存功能的全過程

    社交類軟件聊天功能必不可少,聊天記錄存儲的方式也比較多,比如文本,數(shù)據(jù)庫,云等等,但是最好的選擇還是redis進行存儲,這篇文章主要給大家介紹了關于如何利用redis實現(xiàn)聊天記錄轉存功能的相關資料,需要的朋友可以參考下
    2021-08-08
  • Redis中哈希分布不均勻的解決辦法

    Redis中哈希分布不均勻的解決辦法

    這篇文章主要介紹了Redis中哈希分布不均勻的解決辦法的相關資料,需要的朋友可以參考下
    2021-02-02
  • 淺析Redis中紅鎖RedLock的實現(xiàn)原理

    淺析Redis中紅鎖RedLock的實現(xiàn)原理

    RedLock?是一種分布式鎖的實現(xiàn)算法,由?Redis?的作者?Salvatore?Sanfilippo(也稱為?Antirez)提出,本文主要為大家詳細介紹了紅鎖RedLock的實現(xiàn)原理,感興趣的可以了解下
    2024-02-02
  • redis分布式鎖優(yōu)化的實現(xiàn)

    redis分布式鎖優(yōu)化的實現(xiàn)

    本文主要介紹了redis分布式鎖優(yōu)化的實現(xiàn),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • SpringBoot集成Redis的思路詳解

    SpringBoot集成Redis的思路詳解

    Redis是一個開源的使用ANSI C語言編寫、支持網(wǎng)絡、可基于內(nèi)存亦可持久化的日志型、Key-Value數(shù)據(jù)庫,并提供多種語言的API。接下來通過本文給大家分享SpringBoot集成Redis的詳細過程,感興趣的朋友一起看看吧
    2021-10-10
  • Redis持久化深入詳解

    Redis持久化深入詳解

    這篇文章主要介紹了Redis持久化深入詳解,講解的還是比較詳細的,有感興趣的同學可以學習下
    2021-03-03

最新評論

宁阳县| 庆阳市| 株洲市| 寿光市| 姚安县| 专栏| 大洼县| 连平县| 廉江市| 忻城县| 岢岚县| 永福县| 铅山县| 五家渠市| 英山县| 荥阳市| 外汇| 两当县| 五华县| 来安县| 嵩明县| 武乡县| 弋阳县| 石棉县| 喀什市| 北安市| 邵武市| 蕲春县| 沐川县| 日土县| 务川| 潞城市| 二连浩特市| 大英县| 边坝县| 平凉市| 福安市| 磐安县| 鄂托克旗| 资溪县| 安国市|