基于 Redisson 实现分布式锁

之前业务里面实现分布式锁,是通过redis的计数器来实现的,那种方式当服务宕机时,key会永久保存在redis里面,

所以切到 redisson上,redisson获取锁时解决了死锁问题,底层通过调用lua脚本来实现写入key和设置过期时间的原子性.

更多redisson 的信息可以参考官方文档:

https://yq.aliyun.com/articles/554765?spm=a2c4e.11155435.0.0.634056a3ail7EF

使用条件

jdk 1.6+, redis 2.8+

引入 pom


	org.redisson
	redisson
	3.5.4

注册一个 redisson 客户端service

import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;

/**
 * redis 锁服务
 *
 * @author Demon-HY
 * @date 2019-8-19
 */
@Service
public class RedissonClientService {

    @Value("${redis.host}")
    private String redisHost;

    @Value("${redis.port}")
    private String redisPort;

    @Value("${redis.auth}")
    private String redisAuth;

    @Value("${redis.timeout}")
    private Integer redisTimeout;

    private RedissonClient redissonClient;

    @PostConstruct
    public void afterCreation() {
        Config config = new Config();
        // 单实例模式
        config.useSingleServer()
                .setAddress(String.format("redis://%s:%s", redisHost, redisPort))
                .setPassword(redisAuth)
                // 同任何节点建立连接时的等待超时,时间单位是毫秒,默认:10000
                .setConnectTimeout(30000)
                // 当与某个节点的连接断开时,等待与其重新建立连接的时间间隔,时间单位是毫秒,默认:3000
                .setReconnectionTimeout(10000)
                // 等待节点回复命令的时间,该时间从命令发送成功时开始计时,默认:3000
                .setTimeout(10000)
                // 如果尝试达到 retryAttempts(命令失败重试次数) 仍然不能将命令发送至某个指定的节点时,将抛出错误.
                // 如果尝试在此限制之内发送成功,则开始启用 timeout(命令等待超时) 计时,默认值:3
                .setRetryAttempts(5)
                // 在一条命令发送失败以后,等待重试发送的时间间隔,时间单位是毫秒,默认值:1500
                .setRetryInterval(3000);
        redissonClient = Redisson.create(config);
    }

    /**
     * 获取锁
     *
     * @param lockName 锁名称
     * @return
     */
    public RLock getLock(String lockName) {
        return redissonClient.getLock(lockName);
    }

    /**
     * 根据name对进行上锁操作
     *
     * @param lockName 锁名称
     * @param timeout  超时时间,到期后强制解锁,防止死锁,单位:秒
     * @return
     */
    public void lock(String lockName, long timeout) {
        RLock lock = getLock(lockName);
        //lock提供带timeout参数,timeout结束强制解锁,防止死锁
        lock.lock(timeout, TimeUnit.SECONDS);
    }

    /**
     * 根据name对进行上锁操作,redisson tryLock  根据第一个参数,一定时间内为获取到锁,则不再等待直接返回boolean。交给上层处理
     *
     * @param lockName 锁名称
     * @param waitTime 等待时间,到期后获取不到锁则直接返回,单位:秒
     * @param timeout  获取锁超时时间,到期后强制释放锁,单位:秒
     */
    public boolean tryLock(String lockName, long waitTime, long timeout) throws InterruptedException {
        RLock lock = getLock(lockName);
        //tryLock,第一个参数是等待时间,5秒内获取不到锁,则直接返回。 第二个参数 60是60秒后强制释放
        return lock.tryLock(waitTime, timeout, TimeUnit.SECONDS);
    }

    /**
     * 根据name对进行解锁操作
     *
     * @param lockName 锁名称
     */
    public void unlock(String lockName) {
        RLock lock = getLock(lockName);
        lock.unlock();
    }
}

测试代码

@Autowired
private RedissonClientService redissonClientService;

public void testLock(String lockName) {
    RLock lock = redissonClientService.getLock(lockName);
    try {
        //tryLock,第一个参数是等待时间,0秒内获取不到锁,则直接返回。 第二个参数 是180秒后强制释放
        if (!lock.tryLock(0L, 180L, TimeUnit.SECONDS)) {//获取不到锁,直接返回
            logger.warn("获取锁:{} 失败", lockName);
            return;
        }

        // 获取到锁,执行业务代码
        // ...
    } catch (Exception e) {
        logger.error("业务代码执行异常");
    } finally {
        lock.unlock();
    }
}

 

你可能感兴趣的:(SpringBoot,Java,Java,Redis,SpringBoot)