Redis分散ロックの実装およびツールクラス

7020 ワード

一、適用シーン:
本明細書で適用するシナリオは、データをクエリーする際に、データが存在しないことを発見した場合にデータベースをクエリーし、キャッシュを更新する必要があり、この場合、高同時要求が同時にデータベースにヒットする可能性があるが、この場合にはこれらの要求にロックをかけなければならないため、分散ロック方式が採用されている.(もちろん分散ロックの応用シーンが多く、本人の仕事の業務シーンに対応した処理をしただけです)
二、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を更新し、最後にロックを解除する