亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Redis分布式鎖的原理是什么和怎么實現

發布時間:2022-12-07 09:55:42 來源:億速云 閱讀:148 作者:iii 欄目:開發技術

這篇文章主要介紹了Redis分布式鎖的原理是什么和怎么實現的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇Redis分布式鎖的原理是什么和怎么實現文章都會有所收獲,下面我們一起來看看吧。

1 一人一單并發安全問題

之前一人一單的業務使用的悲觀鎖,在分布式系統下,是無法生效的。

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

Redis分布式鎖的原理是什么和怎么實現

但是問題就出現在:

分布式系統下,有多個不同的JVM,不同的JVM的環境下,鎖監聽器是有多個的,就會出現有的線程在別的線程已經拿到鎖的情況下,仍然可以獲取的到鎖。

Redis分布式鎖的原理是什么和怎么實現

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

2 分布式鎖的原理和實現

2.1 什么是分布式鎖

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

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

Redis分布式鎖的原理是什么和怎么實現

特點:

Redis分布式鎖的原理是什么和怎么實現

2.2 分布式鎖的實現

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

如下圖:

Redis分布式鎖的原理是什么和怎么實現

這里主要講基于Redis的分布式鎖的實現 。

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

1. 獲取鎖

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

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

SET lock thread1 nx ex 10

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

2. 釋放鎖

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

del lock

代碼實現:

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

Redis分布式鎖的原理是什么和怎么實現

代碼如下:

接口代碼:

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

接口實現類:

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;
    //業務名稱,也就是鎖的名稱
    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);
    }
}

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

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>
 *  服務實現類
 * </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.獲取優惠券信息
        SeckillVoucher voucher = iSeckillVoucherService.getById(voucherId);
        //2.判斷是否已經開始
        if (voucher.getBeginTime().isAfter(LocalDateTime.now())){
            Result.fail("秒殺尚未開始!");
        }
        //3.判斷是否已經結束
        if (voucher.getEndTime().isBefore(LocalDateTime.now())){
            Result.fail("秒殺已經結束了!");
        }
        //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.創建鎖對象
        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.根據優惠券id和用戶id判斷訂單是否已經存在
        //如果存在,則返回錯誤信息
        int count = query().eq("user_id", userId).eq("voucher_id", voucherId).count();
        if (count > 0) {
            return Result.fail("用戶已經購買!");
        }
        //7. 創建訂單
        VoucherOrder voucherOrder = new VoucherOrder();
        //7.1添加訂單id
        Long orderId = redisIdWorker.nextId("order");
        voucherOrder.setId(orderId);
        //7.2添加用戶id
        voucherOrder.setUserId(userId);
        //7.3添加優惠券id
        voucherOrder.setVoucherId(voucherId);
        save(voucherOrder);
        //8.返回訂單id
        return Result.ok(orderId);
    }
}

關于“Redis分布式鎖的原理是什么和怎么實現”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“Redis分布式鎖的原理是什么和怎么實現”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

蓝山县| 田东县| 志丹县| 鹤庆县| 迁西县| 鞍山市| 五河县| 霍山县| 奉化市| 渭源县| 铁岭市| 东兰县| 闽清县| 任丘市| 留坝县| 安福县| 读书| 资中县| 张家港市| 东辽县| 汕尾市| 大同市| 朝阳市| 三门峡市| 咸阳市| 罗城| 张北县| 固原市| 观塘区| 高雄市| 冷水江市| 洛川县| 中卫市| 拉孜县| 商都县| 准格尔旗| 靖宇县| 喀喇沁旗| 庄河市| 大名县| 平利县|