希望大佬们帮忙看下代码有没有大的问题,寻求改进的方向,代码的具体业务逻辑不便粘贴,望谅解(磕头)
[!NOTE]
目前代码日志打印有问题
代码逻辑
- 请求逻辑:查询信息,若没有则创建返回
- 并发逻辑:
- 查询数据,有则返回,无则往下
- 获取不到锁,等待 0.2 秒继续第 1 步
- 获取到锁,查询是否有数据,无则添加,完成后释放锁
BaseLockWithData 基类
/**
* 用于处理先查询数据是否存在,不存在则创建的并发问题的分布式锁用到的类
*/
@Data
public class BaseLockWithData<A, S, R> {
/**
* 事务名称
*/
private String txName;
/**
* redis的key
*/
private String key;
/**
* redis的锁的时间(秒)
*/
private long lockTime;
/**
* 超时时间(秒)
*/
private long timeout;
/**
* 添加函数的入参
*/
private A addObj;
/**
* 查询函数的参数
*/
private S searchObj;
/**
* 添加函数
*/
private Function<A, R> addFunction;
/**
* 查询函数
*/
private Function<S, R> searchFunction;
public void setAddFunction(Function<A, R> addFunction, A addObj) {
this.addFunction = addFunction;
this.addObj = addObj;
}
public void setSearchFunction(Function<S, R> searchFunction, S searchObj) {
this.searchFunction = searchFunction;
this.searchObj = searchObj;
}
public BaseLockWithData() {
this.lockTime = 5;
this.timeout = 10;
}
}
具体的锁方法
public <A, S, R> R lockWithData(BaseLockWithData<A, S, R> lockData) {
R data = null;
long timeout = lockData.getTimeout() * 1000;
long startTime = Instant.now().toEpochMilli();
try {
// 获取不到锁则循环获取
while (Instant.now().toEpochMilli() - startTime < timeout) {
data = lockData.getSearchFunction().apply(lockData.getSearchObj());
if (data != null) {
break;
}
// 添加分布式锁
boolean lock = this.lock(lockData.getKey(), lockData.getLockTime());
if (lock) {
TransactionStatus transaction = null;
try {
// 控制添加数据数据的事务
DefaultTransactionDefinition dtd = new DefaultTransactionDefinition();
dtd.setName(lockData.getTxName());
transaction = this.transactionManager.getTransaction(dtd);
// 防止获取锁的过程中其他线程已经添加好数据
data = lockData.getSearchFunction().apply(lockData.getSearchObj());
if (data != null) {
break;
}
data = lockData.getAddFunction().apply(lockData.getAddObj());
this.transactionManager.commit(transaction);
} catch (Exception e) {
if (transaction != null) {
this.transactionManager.rollback(transaction);
}
log.error("事务[{}]错误:错误信息{}", lockData.getTxName(), e.getMessage(), e);
throw new CrmException(RespCodeEnum.SYSTEM_ERROR);
} finally {
this.unlock(lockData.getKey());
}
}
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(100));
}
} catch (Exception e) {
log.info("分布式锁出先问题: {}", e.getMessage(), e);
throw e;
}
if (data == null) {
log.error("未能在指定时间内获取锁或找到数据,锁键:{}, 超时时间:{}ms", lockData.getKey(), timeout);
throw new CrmException(RespCodeEnum.REDIS_LOCK_TIMEOUT);
}
return data;
}