Redis分布式鎖防止超賣

?SETNX ,命令解釋http://redis.cn/commands/setnx.html,GETSET,命令解釋http://redis.cn/commands/getset.html。

public class RedisLock {

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
    *@Description
    *@Date 14:10 2018/6/17
    *@Param value:當(dāng)前時(shí)間+超時(shí)時(shí)間
    *@return
    **/
    public  boolean lock(String key,String value){
        if (redisTemplate.opsForValue().setIfAbsent(key,value)){
            return true;
        }

//下面代碼解決了 死鎖問題 和 保證只有一個(gè)線程拿鎖。
/**1.死鎖 。當(dāng)相關(guān)代碼之前上鎖后,如果執(zhí)行代碼的過程中拋錯(cuò)了,
那么就會(huì)出現(xiàn)沒有解鎖的問題,后續(xù)線程無法獲得鎖,也就出現(xiàn)了死鎖的問題。
而以下代碼后有返回true的可能,也就解決了死鎖問題。
*/
/**2.保證只有一個(gè)線程拿鎖。比如兩個(gè)線程同時(shí)進(jìn)入下面代碼,并且其value都為B,currentValue = A。
一條代碼只可能一個(gè)線程執(zhí)行。
當(dāng)?shù)谝粋€(gè)線程執(zhí)行時(shí),oldvalue = A,如果符合if條件成功拿鎖。
當(dāng)?shù)诙€(gè)執(zhí)行時(shí)oldValue就已經(jīng)是B了,所以保證了只有一個(gè)線程拿鎖。
*/

        String currentValue = redisTemplate.opsForValue().get(key);
        //如果鎖過期
        if (!StringUtils.isEmpty(currentValue) && Long.parseLong(currentValue) < System.currentTimeMillis()){
            //獲取上一個(gè)鎖的時(shí)間
            String oldValue = redisTemplate.opsForValue().getAndSet(key,value);
            if (!StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue)){
                return true;
            }
        }

        return false;
    }

    /**
    *@Author banrityan
    *@Description 解鎖
    *@Date 14:25 2018/6/17
    *@Param
    *@return
    **/
    public void unlock(String key,String value){
        try{
            String currentValue = redisTemplate.opsForValue().get(key);
            if (!StringUtils.isEmpty(currentValue) && currentValue.equals(value)){
                redisTemplate.opsForValue().getOperations().delete(key);
            }
        }catch (Exception e){
            log.error("【redis分布式鎖】解鎖異常,{}",e);
        }
    }
}

?解釋在代碼注釋中。
?然后值需要在要執(zhí)行的代碼前加鎖

        //加鎖
        long time = System.currentTimeMillis() + TIMEOUT;
        if (!redisLock.lock(productId,String.valueOf(time))){
            throw new SellException(101,"哎喲喂,人太多,請稍后再試~~");
        }

?然后執(zhí)行完后記得解鎖

 //解鎖
        redisLock.unlock(productId,String.valueOf(time));

內(nèi)容如上。\( ̄︶ ̄)/

參考資料:無所不知的度娘+各位大佬的博客

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容