• redis分布式锁


    //这个没有重新获取机制,加锁的时候需要 自己在外面while循环 尝试获取锁
    @Component
    public class RedisLockUtil { private static final String REDIS_SUCCESS="OK"; private static final String REDIS_NX="NX"; private static final String REDIS_PX="PX"; private static final String REDIS_SCRIPT="if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; @Autowired private JedisPool jedisPool; public RedisLockUtil() { } public RedisLockUtil(JedisPool jedisPool) { this.jedisPool = jedisPool; } /** * * @param key 锁名 * @param value 锁唯一占用标示 * @param loseTime 锁失效时间,根据程序设定 * @return */ public ReturnBean addLock(String key, String value,Long loseTime){ ReturnBean returnBean = new ReturnBean(); try { if(StringUtil.isEmpty(key) || StringUtil.isEmpty(value)){ throw new BusinessException("key和value值不能为空"); } Jedis jedis = jedisPool.getResource(); String res = jedis.set(key, value, REDIS_NX, REDIS_PX, loseTime); jedis.close(); if(REDIS_SUCCESS.equals(res)){ returnBean.setCode(CommonMsg.SUCCESSCODE); }else{ returnBean.setCode(CommonMsg.ERRORCODE); returnBean.setMsg(key+":锁被占用"); } } catch (Exception e) { returnBean.setCode(CommonMsg.ERRORCODE); if(e instanceof BusinessException){ returnBean.setMsg(e.getMessage()); }else{ returnBean.setMsg("jedis连接异常"); } e.printStackTrace(); } return returnBean; } /** * 释放锁 * @param key * @param value * @return */ public ReturnBean delLock(String key,String value){ ReturnBean returnBean = new ReturnBean(); try { if(StringUtil.isEmpty(key) || StringUtil.isEmpty(value)){ throw new BusinessException("key和value值不能为空"); } Jedis jedis = jedisPool.getResource(); List<String> keyList = new ArrayList<>(); keyList.add(key); List<String> argvList = new ArrayList<>(); argvList.add(value); Long result = (Long) jedis.eval(REDIS_SCRIPT, keyList, argvList); jedis.close(); if(1 != result){ returnBean.setCode(CommonMsg.ERRORCODE); returnBean.setMsg(key+":锁释放失败"); }else{ returnBean.setCode(CommonMsg.SUCCESSCODE); } } catch (BusinessException e) { returnBean.setCode(CommonMsg.ERRORCODE); if(e instanceof BusinessException){ returnBean.setMsg(e.getMessage()); }else{ returnBean.setMsg("jedis连接异常"); } e.printStackTrace(); } return returnBean; } }

    使用:

    public String redisLockTest(){
            String uuid = UUID.randomUUID().toString();
            ReturnBean returnBean = redisLockUtil.addLock(this.getClass().getName(), uuid, 1000 * 60L);
            if(CommonMsg.SUCCESSCODE.equals(returnBean.getCode())){
                System.out.println("获取锁完成......");
                ReturnBean rb = redisLockUtil.delLock(this.getClass().getName(), uuid);
    
                if(CommonMsg.SUCCESSCODE.equals(rb.getCode())){
                    System.out.println("释放锁完成.......");
                }
            }
            return "0000";
        }

      redisTemplate方式:

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.RedisCallback;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.core.StringRedisTemplate;
    import org.springframework.stereotype.Component;
    import org.springframework.util.StringUtils;
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisCluster;
    import redis.clients.jedis.JedisCommands;
    
    import javax.annotation.Resource;
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * @param
     * @author 王晓磊
     * @Description: redis分布式锁
     * @return
     * @throws
     * @date 2019-4-12 16:12
     */
    @Component
    public class RedisLockUtil {
        @Autowired
        private StringRedisTemplate redisTemplate;
    
        public static final String UNLOCK_LUA;
    
        static {
            StringBuilder sb = new StringBuilder();
            sb.append("if redis.call("get",KEYS[1]) == ARGV[1] ");
            sb.append("then ");
            sb.append("    return redis.call("del",KEYS[1]) ");
            sb.append("else ");
            sb.append("    return 0 ");
            sb.append("end ");
            UNLOCK_LUA = sb.toString();
        }
    
        private final Logger logger = LoggerFactory.getLogger(RedisLockUtil.class);
    
    
        //trytime是指当锁被其他进程用时,尝试获取时间,如果为-1则表示一直尝试获取。expire是指获取锁之后,锁的超时时间
        public boolean lock(String key, String value, Long trytime, Long expire) {
            if (trytime == null) trytime = 1000L*60*60;  //获取时间默认1小时
            if (expire == null || expire < 0 ) expire = 10000L;
            long endTime = System.currentTimeMillis() + trytime;
    
            if (trytime == -1) {  //一直获取锁,知道获取为止
                while (true) {
                    if (addLock(key, value, trytime, expire)) {
                        return true;
                    }
                }
            } else {
                while (System.currentTimeMillis() <= endTime) {
                    if (addLock(key, value, trytime, expire)) {
                        return true;
                    }
                }
            }
            return false;
        }
    
        public boolean unlock(String key, String requestId) {
            return delLock(key, requestId);
        }
    
    
        private boolean addLock(String key, String value, long trytime, long expire) {
            try {
                RedisCallback<String> callback = (connection) -> {
                    JedisCommands commands = (JedisCommands) connection.getNativeConnection();
                    return commands.set(key, value, "NX", "PX", expire);
                };
                String result = redisTemplate.execute(callback);
                return !StringUtils.isEmpty(result);
            } catch (Exception e) {
                logger.error("set redis occured an exception", e);
            }
            return false;
        }
    
    
        private boolean delLock(String key, String requestId) {
            // 释放锁的时候,有可能因为持锁之后方法执行时间大于锁的有效期,此时有可能已经被另外一个线程持有锁,所以不能直接删除
            try {
                List<String> keys = new ArrayList<>();
                keys.add(key);
                List<String> args = new ArrayList<>();
                args.add(requestId);
    
                // 使用lua脚本删除redis中匹配value的key,可以避免由于方法执行时间过长而redis锁自动过期失效的时候误删其他线程的锁
                // spring自带的执行脚本方法中,集群模式直接抛出不支持执行脚本的异常,所以只能拿到原redis的connection来执行脚本
                RedisCallback<Long> callback = (connection) -> {
                    Object nativeConnection = connection.getNativeConnection();
                    // 集群模式和单机模式虽然执行脚本的方法一样,但是没有共同的接口,所以只能分开执行
                    // 集群模式
                    if (nativeConnection instanceof JedisCluster) {
    //                    logger.info("集群模式");
                        return (Long) ((JedisCluster) nativeConnection).eval(UNLOCK_LUA, keys, args);
                    }
    
                    // 单机模式
                    else if (nativeConnection instanceof Jedis) {
    //                    logger.info("单机模式");
                        return (Long) ((Jedis) nativeConnection).eval(UNLOCK_LUA, keys, args);
                    }
                    return 0L;
                };
                Long result = redisTemplate.execute(callback);
                return result != null && result > 0;
            } catch (Exception e) {
                logger.error("release lock occured an exception", e);
            } finally {
                // 清除数据
            }
            return false;
        }
    
    }
    人生如修仙,岂是一日间。何时登临顶,上善若水前。
  • 相关阅读:
    为什么我要迁移 SpringBoot 到函数计算
    PolarDBX源码解读系列:DML之Insert流程
    转载 | 从云计算到函数计算
    通过部署流行Web框架掌握Serverless技术
    阿里云云原生一体化数仓 — 湖仓一体新能力解读
    EasyNLP中文文图生成模型带你秒变艺术家
    转载 | 基于函数计算自定义运行时快速部署一个 springboot 项目
    PolarDBX 源码解读:事务的一生
    【20220319】回老家给父亲庆生
    【20220321】连岳摘抄
  • 原文地址:https://www.cnblogs.com/f-society/p/10696157.html
Copyright © 2020-2023  润新知