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); } }