Redisson分布式锁的最佳实践


一、简要说明

此篇文章主要将项目中使用Redisson框架实现分布式锁的代码抽取出来,供大家参考.

二、前言

  1. 首先引入maven依赖
 <dependency>
     <groupId>org.redisson</groupId>
     <artifactId>redisson-spring-boot-starter</artifactId>
     <version>3.16.6</version>
 </dependency>
  1. 配置redis,如果项目中已经配置了redis则不需要进行任何改动.(集群redis或者主从redis需要额外配置,请自行百度!)

三、代码

import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

@Slf4j
@Component
public class DistributedLockUtils {

    @Autowired
    private RedissonClient redissonClient;

    @FunctionalInterface
    public interface LockTemplate {
        /**
         * 执行业务逻辑,无返回值
         */
        void execute();
    }

    @FunctionalInterface
    public interface LockResultTemplate<T> {
        /**
         * 执行业务代码,有返回值
         *
         * @return 业务代码的返回值
         */
        T execute();
    }

    /**
     * 内部使用,用于包装 {@link LockTemplate} 和{@link LockResultTemplate}
     *
     * @param <T>
     */
    @FunctionalInterface
    private interface LockOperation<T> {
        /**
         * 执行业务代码
         *
         * @return 有返回值的情况下返回操作的结果,无返回值的情况下返回null
         */
        T execute();
    }

    /**
     * 获取分布式锁并执行无返回值的操作。
     *
     * @param lockTemplate 无返回值的操作代码函数
     * @param waitTime     获取锁的超时时间(单位:秒)
     * @param lockName     锁的名称函数,用于获取锁的名称
     */
    public void lock(LockTemplate lockTemplate, Integer waitTime, Supplier<String> lockName) {
        // 将LockTemplate转换为LockOperation,执行操作
        LockOperation<Void> lockOperation = () -> {
            lockTemplate.execute();
            return null;
        };

        // 调用通用的execute方法获取锁并执行操作
        execute(lockOperation, waitTime, lockName.get());
    }

    /**
     * 获取分布式锁并执行无返回值的操作。
     * <p>
     * 默认获取锁的超时时间为:10秒
     *
     * @param lockTemplate 无返回值的操作代码函数
     * @param lockName     锁的名称函数,用于获取锁的名称
     */
    public void lock(LockTemplate lockTemplate, Supplier<String> lockName) {
        // 将LockTemplate转换为LockOperation,执行操作
        LockOperation<Void> lockOperation = () -> {
            lockTemplate.execute();
            return null;
        };

        // 调用通用的execute方法获取锁并执行操作
        execute(lockOperation, DistributedLockConstant.LOCK_WAIT_SECONDS, lockName.get());
    }

    /**
     * 获取分布式锁并执行带有返回值的操作。
     *
     * @param lockResultTemplate 带有返回值的操作代码函数
     * @param waitTime           获取锁的超时时间(单位:秒)
     * @param lockName           锁的名称函数,用于获取锁的名称
     * @param <T>                返回值的类型
     * @return 带有返回值的操作的结果
     */
    public <T> T lock(LockResultTemplate<T> lockResultTemplate, Integer waitTime, Supplier<String> lockName) {
        // 将LockResultTemplate转换为LockOperation,执行操作
        LockOperation<T> lockOperation = lockResultTemplate::execute;

        // 调用通用的execute方法获取锁并执行操作,并返回结果
        return execute(lockOperation, waitTime, lockName.get());
    }

    /**
     * 获取分布式锁并执行带有返回值的操作。
     * <p>
     * 默认获取锁的超时时间为:10秒
     *
     * @param lockResultTemplate 带有返回值的操作代码函数
     * @param lockName           锁的名称函数,用于获取锁的名称
     * @param <S>                返回值的类型
     * @return 带有返回值的操作的结果
     */
    public <S> S lock(LockResultTemplate<S> lockResultTemplate, Supplier<String> lockName) {
        // 将LockResultTemplate转换为LockOperation,执行操作
        LockOperation<S> lockOperation = lockResultTemplate::execute;

        // 调用通用的execute方法获取锁并执行操作,并返回结果
        return execute(lockOperation, DistributedLockConstant.LOCK_WAIT_SECONDS, lockName.get());
    }

    /**
     * 执行业务代码
     *
     * @param lockOperation 业务代码的具体实现逻辑
     * @param time          获取锁的超时时间
     * @param lockName      锁名称
     */
    private <T> T execute(LockOperation<T> lockOperation, Integer time, String lockName) {
        RLock lock = null;
        try {
            lock = redissonClient.getLock(lockName);
            try {
                boolean tryLock = lock.tryLock(time, TimeUnit.SECONDS);
                if (!tryLock) {
                    log.error("===> RLock tryLock result false ,[lockName:{}]", lockName);
                    throw new UtilException("获取锁超时,请重试!");
                }
                //执行业务代码
                return lockOperation.execute();
            } catch (InterruptedException e) {
                log.error("===> RLock tryLock InterruptedException,[lockName:{}]", lockName, e);
                throw new UtilException("获取锁失败了,请重试!");
            }
        } finally {
            if (lock != null && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
}

//相关常量类
public class DistributedLockConstant {
    /**
     * 获取锁的超时时间(单位:秒)
     */
    public static final Integer LOCK_WAIT_SECONDS = 10;
}

四、代码说明

  1. 使用了JAVA8的函数式接口将业务逻辑进行了封装
  2. 将redisson获取锁,执行业务代码,释放锁,这些代码进行了抽取,作为统一的方法进行调用
  3. 使用案例
@Service
public class TestServiceImpl{
    @Autowired
    private DistributedLockUtils lockUtils;
		
    //无返回值的案例		
    public void test(){
         lockUtils.lock(() -> {
            log.info("业务代码执行了!");
        }, () -> "kockKey");
	}

    //有返回值的案例		
    public void test01(){
      String result = lockUtils.lock(() -> {
            log.info("业务代码执行了!");
			return "ok"
        }, () -> "kockKey");
	}
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值