基于springboot2 和 redis 手动封装一个分布式锁实现类,仅提供实现类代码

下面是一个基于Spring Boot 2和Redis手动封装的分布式锁实现类的简单示例:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Component
public class DistributedLock {

    private static final Long RELEASE_SUCCESS = 1L;

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 获取分布式锁
     *
     * @param lockKey   锁的key
     * @param clientId  客户端标识,用于释放锁时验证
     * @param expire    锁的过期时间,单位秒
     * @return 是否成功获取锁
     */
    public boolean tryLock(String lockKey, String clientId, long expire) {
        try {
            String script = "if redis.call('set', KEYS[1], ARGV[1], 'NX', 'EX', ARGV[2]) then return 1 else return 0 end";
            RedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);
            Long result = redisTemplate.execute(redisScript, Collections.singletonList(lockKey), clientId, String.valueOf(expire));

            return RELEASE_SUCCESS.equals(result);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 释放分布式锁
     *
     * @param lockKey   锁的key
     * @param clientId  客户端标识,用于验证是否有权限释放锁
     * @return 是否成功释放锁
     */
    public boolean releaseLock(String lockKey, String clientId) {
        try {
            String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
            RedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);
            Long result = redisTemplate.execute(redisScript, Collections.singletonList(lockKey), clientId);

            return RELEASE_SUCCESS.equals(result);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 尝试获取锁,自动续期
     *
     * @param lockKey   锁的key
     * @param clientId  客户端标识,用于释放锁时验证
     * @param expire    锁的过期时间,单位秒
     * @param timeout   尝试获取锁的超时时间,单位毫秒
     * @return 是否成功获取锁
     */
    public boolean tryLockWithRenew(String lockKey, String clientId, long expire, long timeout) {
        try {
            long startTime = System.currentTimeMillis();
            long waitTime = 0;

            while (waitTime < timeout) {
                if (tryLock(lockKey, clientId, expire)) {
                    return true;
                }

                // 休眠一小段时间后重试
                TimeUnit.MILLISECONDS.sleep(100);
                waitTime = System.currentTimeMillis() - startTime;
            }

            return false;
        } catch (InterruptedException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 生成唯一的客户端标识
     *
     * @return 客户端标识
     */
    public String generateClientId() {
        return UUID.randomUUID().toString();
    }
}

上述代码使用了Redis的SET命令来实现分布式锁的获取和释放,并通过Lua脚本确保这两个操作的原子性。在获取锁时,通过SET命令设置键值对,并通过NXEX选项确保只有在键不存在时才设置成功,并设置过期时间;在释放锁时,通过Lua脚本确保只有在键的值(客户端标识)匹配时才删除键。同时提供了一个可选的自动续期功能,以确保在业务执行时间较长的情况下锁不会过早失效。

请注意,这只是一个简单的示例,实际应用中需要根据具体情况进行适当的调整和优化。在生产环境中使用分布式锁时,还需要考虑锁的超时时间、异常处理、锁的粒度等因素。


import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RequestMapping("/p10")
@RestController
public class P10 {

    @Autowired
    DistributedLock distributedLock;

    @GetMapping("/t1")
    public String t1() {
        boolean b = distributedLock.tryLock("tan", "tt", 500);
        log.info(b+"");

        boolean b1 = distributedLock.releaseLock("tan", "tt");

        log.info(b1+"");

        return null;
    }

}

你可能感兴趣的:(redis,分布式,数据库)