spring boot手动实现Redis分布式锁


import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisCommands;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;


@Component
public class RedisDistributedLock {
     

    /* 加锁成功返回值 */
    private static final String LOCK_SUCCESS = "OK";

    /* 锁不存在时才去设置 */
    private static final String SET_IF_NOT_EXIST = "NX";

    /* 设置过期时间标识 */
    private static final String SET_WITH_EXPIRE_TIME = "PX";

    /* 解锁lua脚本 */
    private static final String UNLOCK_LUA = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 尝试获取分布式锁
     *
     * @param key        锁的Key
     * @param requestId  请求的ID, 区分不同请求, 防止所被其他请求解开
     * @param expireTime 过期时间
     * @param timeUnit   时间单位
     * @return true: 获取锁成功, false: 获取锁失败
     */
    public boolean tryGetDistributedLock(String key, String requestId, long expireTime, TimeUnit timeUnit) {
     
        try {
     
            RedisCallback<String> callback = (connection) -> {
     
                JedisCommands commands = (JedisCommands) connection.getNativeConnection();
                return commands.set(key, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, timeUnit.toMillis(expireTime));
            };
            return LOCK_SUCCESS.equals(redisTemplate.execute(callback));
        } catch (Exception e) {
     
            LogUtils.error("set redis occured an exception", e);
        }
        return false;
    }

    /**
     * 释放分布式锁
     *
     * @param key       锁key值
     * @param requestId 请求ID
     * @return true: 释放成功, false: 释放失败
     */
    public boolean releaseDistributedLock(String key, String requestId) {
     
        // 释放锁的时候,有可能因为持锁之后方法执行时间大于锁的有效期,此时有可能已经被另外一个线程持有锁,所以不能直接删除
        try {
     
            List<String> keys = Collections.singletonList(key);
            List<String> args = Collections.singletonList(requestId);
            // 使用lua脚本删除redis中匹配value的key,可以避免由于方法执行时间过长而redis锁自动过期失效的时候误删其他线程的锁
            // spring自带的执行脚本方法中,集群模式直接抛出不支持执行脚本的异常,所以只能拿到原redis的connection来执行脚本
            RedisCallback<Long> callback = (connection) -> {
     
                Object nativeConnection = connection.getNativeConnection();
                // 集群模式和单机模式虽然执行脚本的方法一样,但是没有共同的接口,所以只能分开执行
                // 集群模式
                if (nativeConnection instanceof JedisCluster) {
     
                    return (Long) ((JedisCluster) nativeConnection).eval(UNLOCK_LUA, keys, args);
                }
                // 单机模式
                else if (nativeConnection instanceof Jedis) {
     
                    return (Long) ((Jedis) nativeConnection).eval(UNLOCK_LUA, keys, args);
                }
                return 0L;
            };
            Long result = redisTemplate.execute(callback);
            return result != null && result > 0;
        } catch (Exception e) {
     
            LogUtils.error("release lock occured an exception", e);
        }
        return false;
    }

}

private void doSome(List<POJO> list) {
     

                String lockeds = null, lockRequestId = UUID.randomUUID().toString();
                try {
     
                    
                    if (!redisDistributedLock.tryGetDistributedLock(lockeds, lockRequestId, requestLock.getTimeout(), requestLock.getUnit())) {
     
                        LogUtils.info("分布式锁已存在,=" + bdmCarBOMTreeMdl.getMtlNO() + ", 锁=" + lockeds);
                        return;
                    }
                    LogUtils.info("加分布式锁成功,=" + bdmCarBOMTreeMdl.getMtlNO() + ", 锁=" + lockeds);



                    System.out.println("执行锁内业务。。。。。。。");




                } catch (Exception e) {
     
                    LogUtils.error(ContractConstants.ERROR, e);
                } finally {
     

                    if (!redisDistributedLock.releaseDistributedLock(lockeds, lockRequestId)) {
     
                        LogUtils.warn("解分布式锁失败, 请求参数=" + bdmCarBOMTreeMdl + ", 物料号=" + bdmCarBOMTreeMdl.getMtlNO() + ", 锁=" + lockeds);
                    } else {
     
                        LogUtils.info("分布式解锁成功,物料号=" + bdmCarBOMTreeMdl.getMtlNO() + ", 锁=" + lockeds);
                    }
                }
            });
        });

你可能感兴趣的:(spring boot手动实现Redis分布式锁)