記一個Redis分布式事務鎖


package com.mall.common;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPool;

@Slf4j
public class DisLock { @Autowired private RedisTemplate<String, Object> redisTemplate; // RedisTemplate public void oneLock(){ String key = "key-001"; Long currentTime = System.currentTimeMillis(); boolean lock = redisTemplate.opsForValue().setIfAbsent(key, currentTime); try { if (lock) { log.info("獲取鎖成功,開始邏輯處理"); }else{ log.info("獲取鎖失敗,業務正在處理中,請稍后"); } }catch (Exception e){ log.error("系統異常",e); }finally { if (lock) { redisTemplate.delete(key); log.info("處理結束,釋放鎖!"); } else { log.info("沒有獲取到鎖,無需釋放鎖!"); Long createTime = (Long) redisTemplate.opsForValue().get(key); Long nowTime = System.currentTimeMillis(); Long time = (nowTime - createTime) / 1000; log.info("沒有獲取到鎖,檢測獲取鎖的線程是否處理超時,超時則釋放他的鎖"); if (time > 10) {//自定義鎖多久自動釋放鎖 redisTemplate.delete(key); log.info("邏輯處理超過20秒,釋放鎖!"); } } } } //jds public void twoLock() { //基於redis的分布式鎖 String redisKey = "key-001"; boolean falg = false; try { Long lock = this.incrBy(redisKey, 1, 10);//一次,超時時間10秒 if (lock > 1) { log.info("請勿重復提交請求"); } log.info("邏輯處理開始。。。。"); } catch (Exception e) { log.error("#accumulatePoints() 出現異常:{}", e); } finally { if(falg) { this.del(redisKey); } } } static ShardedJedisPool pool; public static Long incrBy(String key, long num, int seconds) { ShardedJedis jds = null; jds = pool.getResource(); Long result = jds.incrBy(key, num); if (seconds > 0) { jds.expire(key, seconds); } return result; } public static void del(String key) { ShardedJedis jds = null; try { jds = pool.getResource(); jds.del(key); } catch (Exception e) { log.error("#RedisPool() del異常:", e); e.printStackTrace(); } } }

 

 

 

 

package com.redis.mq.util;

import redis.clients.jedis.Jedis;

import java.util.Collections;
import java.util.UUID;

/**
 * @author xiaowu
 * @date 2019-12-20
 **/
public class RedisLock {
    /**
     * RedisLock的正確姿勢
     * 加鎖:
     * 通過setnx 向特定的key寫入一個隨機數,並設置失效時間,寫入成功即加鎖成功
     * 注意點:
     *  必須給鎖設置一個失效時間            ----->    避免死鎖
     *  加鎖時,每個節點產生一個隨機字符串    ----->    避免鎖誤刪
     *  寫入隨機數與設置失效時間必須是同時    ----->    保證加鎖的原子性
     *  使用:
     *      SET key value NX PX 3000
     *
     * 解鎖:
     *  匹配隨機數,刪除redis上的特定的key數據,
     *  要保證獲取數據,判斷一致以及刪除數據三個操作是原子性
     *  執行如下lua腳本:
     *      if redis.call('get', KEYS[1]) == ARGV[1] then
     *          return redis.call('del', KEYS[1])
     *      else
     *          return 0
     *      end
     *
     */
    // 使用jedis 客戶端的
    /**SET key value NX PX 3000 成功返回值*/
    private static final String LOCK_SUCCESS = "OK";
    /**表示 NX 模式*/
    private static final String SET_IF_NOT_EXIST = "NX";
    /**單位 毫秒**/
    private static final String SET_WITH_EXPIRE_TIME_PX = "PX";
    /**lua腳本**/
    private static final String SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
    /**存儲隨機數**/
    private static final ThreadLocal<String> local = new ThreadLocal<>();
    /**
     * 加鎖
     */
    public static boolean lock(Jedis jedis, String key, int expireTime) {
        // 產生隨機數
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");

        String result = jedis.set(key, uuid, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME_PX, expireTime);

        if (LOCK_SUCCESS.equals(result)) {
            // 隨機數綁定線程
            local.set(uuid);
            return true;
        }
        return false;
    }

   /**
     * 釋放分布式鎖
     */
    public static boolean unLock(Jedis jedis, String key) {

        String uuid = local.get();
        //當前線程沒有綁定uuid
        //直接返回
        if (uuid == null || "".equals(uuid)) {
            return false;
        }
        
        Object result = jedis.eval(SCRIPT, Collections.singletonList(key), Collections.singletonList(uuid));

        if (Long.valueOf(1).equals(result)) {
            // 解除綁定線程的隨機數
            local.remove();
            return true;
        }
        return false;
    }

    public static void main(String[] args) {
        Jedis jedis = new Jedis("localhost", 6379);
        jedis.auth("373616885");
        jedis.select(0);
        final String LOCK_KEY = "LOCK_KEY";       
        RedisLock.lock(jedis,LOCK_KEY,5000);
        RedisLock.unLock(jedis,LOCK_KEY);
    }

}

 


免責聲明!

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



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