Redisson工具介绍
- 锁是保护资源的一种实现方式,事务也是受保护的资源,所以必须是锁包裹事务,事务必须要在锁内执行
- 此工具类方便快捷的使用redis分布式锁,提高开发效率
- 完整代码封装如下:不废话直接上代码
//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);
<T> T lock(String lockName, int lockTime, RedissonLockWorker<T> worker);
<T> T multiLock(List<String> lockNames, RedissonLockWorker<T> worker);
<T> T multiLock(List<String> lockNames, int lockTime, RedissonLockWorker<T> worker);
void lockVoid(String lockName, RedissonLockWorker<Void> worker);
void lockVoid(String lockName, int lockTime, RedissonLockWorker<Void> worker);
void multiLockVoid(List<String> lockNames, RedissonLockWorker<Void> worker);
void multiLockVoid(List<String> lockNames, int lockTime, RedissonLockWorker<Void> worker);
void unLock(String lockName);
//以下是携带事务的锁
<T> T lockTransaction(String lockName, RedissonLockWorker<T> worker);
<T> T lockTransaction(String lockName, int lockTime, RedissonLockWorker<T> worker);
<T> T multiLockTransaction(List<String> lockNames, RedissonLockWorker<T> worker);
<T> T multiLockTransaction(List<String> lockNames, int lockTime, RedissonLockWorker<T> worker);
void lockTransactionVoid(String lockName, RedissonLockWorker<Void> worker);
void lockTransactionVoid(String lockName, int lockTime, RedissonLockWorker<Void> worker);
void multiLockTransactionVoid(List<String> lockNames, RedissonLockWorker<Void> worker);
void multiLockTransactionVoid(List<String> lockNames, int lockTime, RedissonLockWorker<Void> worker);
}
//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 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) {
boolean acquired = false;
try {
acquired = lock.tryLock(MAX_WAIT_TIME, lockTime, TimeUnit.SECONDS);
if (acquired) {
String lockName = (lock instanceof RedissonMultiLock) ? "multi-lock" : lock.getName();
log.info("Thread {} acquired lock {}", Thread.currentThread().getName(), lockName);
return worker.execute();
} else {
String lockName = (lock instanceof RedissonMultiLock) ? "multi-lock" : lock.getName();
log.error("Thread {} failed to acquire lock {}", Thread.currentThread().getName(), lockName);
throw new RedissonLockException("系统业务繁忙,请稍后再试");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
String lockName = (lock instanceof RedissonMultiLock) ? "multi-lock" : lock.getName();
log.error("Thread {} was interrupted while acquiring lock {}", Thread.currentThread().getName(), lockName, e);
throw new RedissonLockException("系统异常终止,请稍后再试");
} catch (Exception e) {
Thread.currentThread().interrupt();
String lockName = (lock instanceof RedissonMultiLock) ? "multi-lock" : lock.getName();
log.error("Thread {} was interrupted while acquiring lock {}", Thread.currentThread().getName(), lockName, e);
throw new RedissonLockException("系统未知异常,请稍后再试");
} finally {
if (acquired) {
try {
lock.unlock();
String lockName = (lock instanceof RedissonMultiLock) ? "multi-lock" : lock.getName();
log.info("Thread {} released lock {}", Thread.currentThread().getName(), lockName);
} catch (Exception e) {
String lockName = (lock instanceof RedissonMultiLock) ? "multi-lock" : lock.getName();
log.error("Thread {} failed to release lock {}", Thread.currentThread().getName(), lockName, e);
}
}
}
}
private <T> T executeWithTransaction(RLock lock, int lockTime, RedissonLockWorker<T> worker) {
return executeWithLock(lock, lockTime, () -> {
return transactionTemplate.execute(status -> {
try {
return worker.execute();
} catch (Exception e) {
status.setRollbackOnly();
log.error("Execution failed within the lock, transaction rolled back", e);
throw new RuntimeException("系统执行异常,请稍后再试");
}
});
});
}
@Override
public boolean lock(String lockName) {
RLock rLock = getLock(lockName);
return executeWithLock(rLock, LOCK_EXPIRE, () -> true);
}
@Override
public <T> T lock(String lockName, RedissonLockWorker<T> worker) {
return lock(lockName, LOCK_EXPIRE, worker);
}
@Override
public <T> T lock(String lockName, int lockTime, RedissonLockWorker<T> worker) {
RLock rLock = getLock(lockName);
return executeWithLock(rLock, lockTime, worker);
}
@Override
public <T> T multiLock(List<String> lockNames, RedissonLockWorker<T> worker) {
return multiLock(lockNames, LOCK_EXPIRE, worker);
}
@Override
public <T> T multiLock(List<String> lockNames, int lockTime, RedissonLockWorker<T> worker) {
RedissonMultiLock multiLock = getMultiLock(lockNames);
return executeWithLock(multiLock, lockTime, worker);
}
@Override
public void lockVoid(String lockName, RedissonLockWorker<Void> worker) {
lockVoid(lockName, LOCK_EXPIRE, worker);
}
@Override
public void lockVoid(String lockName, int lockTime, RedissonLockWorker<Void> worker) {
RLock rLock = getLock(lockName);
executeWithLock(rLock, lockTime, () -> {
worker.execute();
return null;
});
}
@Override
public void multiLockVoid(List<String> lockNames, RedissonLockWorker<Void> worker) {
multiLockVoid(lockNames, LOCK_EXPIRE, worker);
}
@Override
public void multiLockVoid(List<String> lockNames, int lockTime, RedissonLockWorker<Void> worker) {
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) {
return lockTransaction(lockName, LOCK_EXPIRE, worker);
}
@Override
public <T> T lockTransaction(String lockName, int lockTime, RedissonLockWorker<T> worker) {
RLock rLock = getLock(lockName);
return executeWithTransaction(rLock, lockTime, worker);
}
@Override
public <T> T multiLockTransaction(List<String> lockNames, RedissonLockWorker<T> worker) {
return multiLockTransaction(lockNames, LOCK_EXPIRE, worker);
}
@Override
public <T> T multiLockTransaction(List<String> lockNames, int lockTime, RedissonLockWorker<T> worker) {
RedissonMultiLock multiLock = getMultiLock(lockNames);
return executeWithTransaction(multiLock, lockTime, worker);
}
@Override
public void lockTransactionVoid(String lockName, RedissonLockWorker<Void> worker) {
lockTransactionVoid(lockName, LOCK_EXPIRE, worker);
}
@Override
public void lockTransactionVoid(String lockName, int lockTime, RedissonLockWorker<Void> worker) {
RLock rLock = getLock(lockName);
executeWithTransaction(rLock, lockTime, () -> {
worker.execute();
return null;
});
}
@Override
public void multiLockTransactionVoid(List<String> lockNames, RedissonLockWorker<Void> worker) {
multiLockTransactionVoid(lockNames, LOCK_EXPIRE, worker);
}
@Override
public void multiLockTransactionVoid(List<String> lockNames, int lockTime, RedissonLockWorker<Void> worker) {
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();
});
}