Redisson工具介绍

  1. 锁是保护资源的一种实现方式,事务也是受保护的资源,所以必须是锁包裹事务,事务必须要在锁内执行
  2. 此工具类方便快捷的使用redis分布式锁,提高开发效率
  3. 完整代码封装如下:不废话直接上代码
//RedissonLockException
public class RedissonLockException extends RuntimeException {

    public RedissonLockException(String message) {
        super(message);
    }

    public RedissonLockException(String message, Throwable cause) {
        super(message, cause);
    }

    public RedissonLockException(Throwable cause) {
        super(cause);
    }

    public RedissonLockException() {
        super();
    }
}
//RedissonLockWorker
public interface RedissonLockWorker<T> {

    /**
     * 获取锁成功后执行业务逻辑
     *
     * @return 业务逻辑对象
     * @throws Exception 异常信息
     */
    T execute() throws Exception;
}
//RedissonLockService
public interface RedissonLockService {

    boolean lock(String lockName) throws Exception;

    <T> T lock(String lockName, RedissonLockWorker<T> worker) throws Exception;

    <T> T lock(String lockName, int lockTime, RedissonLockWorker<T> worker) throws Exception;

    <T> T multiLock(List<String> lockNames, RedissonLockWorker<T> worker) throws Exception;

    <T> T multiLock(List<String> lockNames, int lockTime, RedissonLockWorker<T> worker) throws Exception;

    void lockVoid(String lockName, RedissonLockWorker<Void> worker) throws Exception;

    void lockVoid(String lockName, int lockTime, RedissonLockWorker<Void> worker) throws Exception;

    void multiLockVoid(List<String> lockNames, RedissonLockWorker<Void> worker) throws Exception;

    void multiLockVoid(List<String> lockNames, int lockTime, RedissonLockWorker<Void> worker) throws Exception;

    void unLock(String lockName);


    //以下是携带事务的锁
    <T> T lockTransaction(String lockName, RedissonLockWorker<T> worker) throws Exception;

    <T> T lockTransaction(String lockName, int lockTime, RedissonLockWorker<T> worker) throws Exception;

    <T> T multiLockTransaction(List<String> lockNames, RedissonLockWorker<T> worker) throws Exception;

    <T> T multiLockTransaction(List<String> lockNames, int lockTime, RedissonLockWorker<T> worker) throws Exception;


    void lockTransactionVoid(String lockName, RedissonLockWorker<Void> worker) throws Exception;

    void lockTransactionVoid(String lockName, int lockTime, RedissonLockWorker<Void> worker) throws Exception;

    void multiLockTransactionVoid(List<String> lockNames, RedissonLockWorker<Void> worker) throws Exception;

    void multiLockTransactionVoid(List<String> lockNames, int lockTime, RedissonLockWorker<Void> worker) throws Exception;
//RedissonLocker
@Component
@Slf4j
@RequiredArgsConstructor
public class RedissonLocker implements RedissonLockService {

    private static final int LOCK_EXPIRE = 30;
    private static final int MAX_WAIT_TIME = 10;
    private final RedissonClient redissonClient;
    private final TransactionTemplate transactionTemplate;
    //最大持有锁超时时间: 单位秒
    private static final int MAX_HOLD_TIME = 4;

    private RedissonMultiLock getMultiLock(List<String> lockNames) {
        if (CollectionUtil.isEmpty(lockNames)) {
            throw new IllegalArgumentException("lockNames cannot be empty");
        }
        RLock[] locks = new RLock[lockNames.size()];
        for (int i = 0; i < lockNames.size(); i++) {
            locks[i] = getLock(lockNames.get(i));
        }
        return new RedissonMultiLock(locks);
    }

    private RLock getLock(String lockName) {
        if (StrUtil.isBlank(lockName)) {
            throw new IllegalArgumentException("lockName cannot be empty");
        }
        return redissonClient.getLock(lockName);
    }

    private <T> T executeWithLock(RLock lock, int lockTime, RedissonLockWorker<T> worker) throws Exception {
        long startTime = System.nanoTime();
        String lockName = (lock instanceof RedissonMultiLock) ? "multi-lock" : lock.getName();
        boolean acquired = false;

        try {
            acquired = lock.tryLock(MAX_WAIT_TIME, lockTime, TimeUnit.SECONDS);
            if (!acquired) {
                log.error("线程 {} 未能获取锁 {}", Thread.currentThread().getName(), lockName);
                throw new RedissonLockException("系统业务繁忙,请稍后再试");
            }

            log.info("线程 {} 获取了锁 {}", Thread.currentThread().getName(), lockName);
            return worker.execute();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("线程 {} 获取锁时被中断 {}", Thread.currentThread().getName(), lockName, e);
            throw new RedissonLockException("系统异常终止,请稍后再试");
        } catch (RedissonLockException e) {
            // RedissonLockException 已经记录了日志
            throw e;
        } catch (Exception e) {
            log.error("线程 {} 获取锁时遇到异常 {}", Thread.currentThread().getName(), lockName, e);
            //将异常原封不不动的抛出去
            throw e;
        } finally {
            long endTime = System.nanoTime();
            long holdTime = (endTime - startTime) / 1_000_000;
            //转换成秒
            log.info("线程 {} 持有锁 {} 的时间为 {} 毫秒", Thread.currentThread().getName(), lockName, holdTime);
            if (holdTime > MAX_HOLD_TIME * 1000) {
                log.error("线程 {} 持有锁 {} 的时间超过 {} 毫秒,此方法应该被重点关注", Thread.currentThread().getName(), lockName, MAX_HOLD_TIME);
            }
            if (acquired) {
                try {
                    lock.unlock();
                    log.info("线程 {} 释放了锁 {}", Thread.currentThread().getName(), lockName);
                } catch (Exception e) {
                    log.error("线程 {} 释放锁时失败 {}", Thread.currentThread().getName(), lockName, e);
                }
            }
        }
    }

    private <T> T executeWithTransaction(RLock lock, int lockTime, RedissonLockWorker<T> worker) throws Exception {
        return executeWithLock(lock, lockTime, () -> transactionTemplate.execute(status -> {
            try {
                return worker.execute();
            } catch (Exception e) {
                if (!status.isCompleted()) {
                    status.setRollbackOnly();
                }
                log.error("锁内业务执行失败,事务回滚", e);
                throw new RuntimeException("系统执行异常,请稍后再试");
            }
        }));
    }


    @Override
    public boolean lock(String lockName) throws Exception {
        RLock rLock = getLock(lockName);
        return executeWithLock(rLock, LOCK_EXPIRE, () -> true);
    }


    @Override
    public <T> T lock(String lockName, RedissonLockWorker<T> worker) throws Exception {
        return lock(lockName, LOCK_EXPIRE, worker);
    }


    @Override
    public <T> T lock(String lockName, int lockTime, RedissonLockWorker<T> worker) throws Exception {
        RLock rLock = getLock(lockName);
        return executeWithLock(rLock, lockTime, worker);
    }


    @Override
    public <T> T multiLock(List<String> lockNames, RedissonLockWorker<T> worker) throws Exception {
        return multiLock(lockNames, LOCK_EXPIRE, worker);
    }


    @Override
    public <T> T multiLock(List<String> lockNames, int lockTime, RedissonLockWorker<T> worker) throws Exception {
        RedissonMultiLock multiLock = getMultiLock(lockNames);
        return executeWithLock(multiLock, lockTime, worker);
    }


    @Override
    public void lockVoid(String lockName, RedissonLockWorker<Void> worker) throws Exception {
        lockVoid(lockName, LOCK_EXPIRE, worker);
    }

    @Override
    public void lockVoid(String lockName, int lockTime, RedissonLockWorker<Void> worker) throws Exception {
        RLock rLock = getLock(lockName);
        executeWithLock(rLock, lockTime, () -> {
            worker.execute();
            return null;
        });
    }


    @Override
    public void multiLockVoid(List<String> lockNames, RedissonLockWorker<Void> worker) throws Exception {
        multiLockVoid(lockNames, LOCK_EXPIRE, worker);
    }

    @Override
    public void multiLockVoid(List<String> lockNames, int lockTime, RedissonLockWorker<Void> worker) throws Exception {
        RedissonMultiLock multiLock = getMultiLock(lockNames);
        executeWithLock(multiLock, lockTime, () -> {
            worker.execute();
            return null;
        });
    }


    @Override
    public void unLock(String lockName) {
        RLock rLock = getLock(lockName);
        if (rLock.isLocked()) {
            log.info("Thread {} is releasing the lock {}", Thread.currentThread().getName(), lockName);
            try {
                rLock.unlock();
                log.info("Thread {} released the lock {}", Thread.currentThread().getName(), lockName);
            } catch (Exception e) {
                log.error("Thread {} failed to release lock {}", Thread.currentThread().getName(), lockName, e);
            }
        } else {
            log.error("Thread {} tried to release a lock it does not hold {}", Thread.currentThread().getName(), lockName);
        }
    }

    @Override
    public <T> T lockTransaction(String lockName, RedissonLockWorker<T> worker) throws Exception {
        return lockTransaction(lockName, LOCK_EXPIRE, worker);
    }


    @Override
    public <T> T lockTransaction(String lockName, int lockTime, RedissonLockWorker<T> worker) throws Exception {
        RLock rLock = getLock(lockName);
        return executeWithTransaction(rLock, lockTime, worker);
    }

    @Override
    public <T> T multiLockTransaction(List<String> lockNames, RedissonLockWorker<T> worker) throws Exception {
        return multiLockTransaction(lockNames, LOCK_EXPIRE, worker);
    }

    @Override
    public <T> T multiLockTransaction(List<String> lockNames, int lockTime, RedissonLockWorker<T> worker) throws Exception {
        RedissonMultiLock multiLock = getMultiLock(lockNames);
        return executeWithTransaction(multiLock, lockTime, worker);
    }

    @Override
    public void lockTransactionVoid(String lockName, RedissonLockWorker<Void> worker) throws Exception {
        lockTransactionVoid(lockName, LOCK_EXPIRE, worker);
    }

    @Override
    public void lockTransactionVoid(String lockName, int lockTime, RedissonLockWorker<Void> worker) throws Exception {
        RLock rLock = getLock(lockName);
        executeWithTransaction(rLock, lockTime, () -> {
            worker.execute();
            return null;
        });
    }


    @Override
    public void multiLockTransactionVoid(List<String> lockNames, RedissonLockWorker<Void> worker) throws Exception {
        multiLockTransactionVoid(lockNames, LOCK_EXPIRE, worker);
    }


    @Override
    public void multiLockTransactionVoid(List<String> lockNames, int lockTime, RedissonLockWorker<Void> worker) throws Exception {
        RedissonMultiLock multiLock = getMultiLock(lockNames);
        executeWithTransaction(multiLock, lockTime, () -> {
            worker.execute();
            return null;
        });
    }


}

使用范例

    @Override
    public R distributionGiftPack(DistributionGiftPackDTO dto) {
        if (dto == null) {
            return R.failed("参数不能为空");
        }
        //TODO 其他参数判断
        return redissonLockService.lockTransaction(ActivityRedisKey.AC_KEY + dto.getActivityId(), () -> {
            virtualService.distributionGiftPack(dto.getActivityId(), dto.getCustomId(), dto.getCustomName(), dto.getOrderId(), dto.getGoodsIdList());
            return R.ok();
        });
    }
Logo

更多推荐