• 记一个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);
        }
    
    }
  • 相关阅读:
    2016/4/7 省市县三级联动 下拉菜单式
    2016/4/5 Ajax ①用户名 密码 登陆 注册 ② 判断用户名是否已存在 ③点击按钮出现民族选项下拉菜单 ④DBDA类 加入Ajaxquery方法 数组变字符串 字符串拆分
    2016/4/2 json:js和jquery中轻量级数据交换格式 例: 窗口弹出 popwindow
    2016/4/1 jquery 与javascript关系 ①取元素 ②操作内容 ③操作属性 ④操作 样式 ⑤ 事件 点击变色
    2016/4/1 PDO:: 数据访问抽象层 ? :
    2016/3/31 ①全选时 下面选项全选中 ② 下面不选中时 全选取消 ③在“” 中 转义字符的使用 onclick="Checkpa(this,'flall')"; ④区别于分别实现 重点在于两种情况合并实现
    2016/3/30 租房子 ①建立租房子的增、删、改php页面 ②多条件查询 ③全选时 各部分全选中 任意checkbox不选中 全选checkbox不选中
    正则表达式
    HTML总结
    深入理解CSS盒子模型
  • 原文地址:https://www.cnblogs.com/mr-wuxiansheng/p/12072095.html
Copyright © 2020-2023  润新知