Redis分布式鎖的實現以及工具類


一、應用場景:

  本文應用的場景為在查詢數據時,發現數據不存在此時就需要去查詢數據庫並且更新緩存,此時可能存在高並發的請求同時打在數據庫上,而針對這種情況必須要給這些請求加鎖,故而采用了分布式鎖的方式。(當然分布式鎖的應用場景較多,我只是針對本人工作的業務場景做了對應的處理)

二、Redis鎖的工具類:

/**
 * Redis分布式鎖
 */
@Component
public class RedisLock {

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 加鎖
     * @param key
     * @param value 當前時間+超時時間
     * @return
     */
    public boolean lock(String key, String value) {
    
        if(redisTemplate.opsForValue().setIfAbsent(key, value)) {//相當於SETNX,setIfAbsent方法設置了為true,沒有設置為false
            return true;
        }
        //假設currentValue=A   接下來並發進來的兩個線程的value都是B  其中一個線程拿到鎖,除非從始至終所有都是在並發(實際上這中情況是不存在的),只要開始時有數據有先后順序,則分布式鎖就不會出現“多賣”的現象
        String currentValue = String.valueOf(redisTemplate.opsForValue().get(key));
        //如果鎖過期  解決死鎖
        if (!StringUtils.isEmpty(currentValue)
                && Long.parseLong(currentValue) < System.currentTimeMillis()) {
            //獲取上一個鎖的時間,鎖過期后,GETSET將原來的鎖替換成新鎖
            String oldValue = String.valueOf(redisTemplate.opsForValue().getAndSet(key, value));
            if (!StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue)) {
                return true;
            }
        }

        return false;//拿到鎖的就有執行權力,拿不到的只有重新再來,重新再來只得是讓用戶手動繼續搶單
    }

    /**
     * 解鎖
     * @param key
     * @param value
     */
    public void unlock(String key, String value) {
        try {
            String currentValue = String.valueOf(redisTemplate.opsForValue().get(key));
            if (!StringUtils.isEmpty(currentValue) && currentValue.equals(value)) {
                redisTemplate.opsForValue().getOperations().delete(key);
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
    }

}

三、業務代碼:

JSONArray allApplyForms = null;
if (this.redisActivityService.exists(RedisKeys.ApplyFormList_KEY+String.valueOf(activityId))) {
  // 如果redis緩存在有該活動的作品列表,則直接從redis中獲取 Object allApplyFormsJSON = this.redisActivityService.get(RedisKeys.ApplyFormList_KEY+String.valueOf(activityId)); allApplyForms = JSONArray.fromObject(allApplyFormsJSON.toString());
}
else { long time = System.currentTimeMillis()+(20 * 1000); if(!redisLock.lock("ApplyFormListLock", String.valueOf(time))){ return CORSUtil.getResult(0, "當前訪問量大,刷新一下", null, callback); } allApplyForms = this.activityService.getAllApplyForms(activityId, thumbnailWidth,thumbnailHeight, contentCode, formTitle, flag,formModel); if(allApplyForms ==null){ return CORSUtil.getResult(0, "沒有對應的參選表單", null,callback); } this.redisActivityService.set(RedisKeys.ApplyFormList_KEY+String.valueOf(activityId), allApplyForms.toString(),Long.parseLong(systemConfigService.getConfig("redisOverTime"))+new Random().nextInt(200)); redisLock.unlock("ApplyFormListLock", String.valueOf(time)); }

1,從redis中獲取對應的數據,如果獲取到直接返回,如果沒有就走接下來的加鎖代碼

2,如果加鎖不成功,則說明已經有請求進入到后面的業務邏輯,這時候就直接返回給客戶端,等待

3,如果加鎖成功,則查詢數據並更新Redis,最后再釋放鎖

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM