为了方便我们在削减库存的时候可以对库存进行更新操作。我们在递减库存前还需要借助于另一把锁。 这一把锁我们叫做【a_key】
换句话说我们接口想访问就必须获取【a】锁,拿到【a】锁需要减少库存。减少库存之前需要获取【a_key】锁。
拿到锁之后处理完逻辑之后我们需要释放对应锁。
RedisAtomicLong entityIdCounter = new RedisAtomicLong(lockKey, redisTemplate.getConnectionFactory());
if (redisTemplate.hasKey(CoreConstants.UPDATEPRODUCTREDISLOCKKEY + lockKey)) {
//表示lockKey的库存信息有变动。此时无法进行交易
throw new BusinessException("库存变动。暂无法交易");
}
Long increment = entityIdCounter.decrementAndGet();
if (increment >= 0) {
try {
Object proceed = pjp.proceed();
} catch (Throwable throwable) {
//所占资源需要释放回资源池
while (!redisLock.tryGetLock(CoreConstants.UPDATEPRODUCTREDISLOCKKEY + lockKey, "")) {
}
//表示lockKey的库存信息有变动。此时无法进行交易
long l = entityIdCounter.incrementAndGet();
if (l < 1) {
redisTemplate.opsForValue().set(lockKey,1);
}
redisLock.unLock(CoreConstants.UPDATEPRODUCTREDISLOCKKEY + lockKey);
throwable.printStackTrace();
}
} else {
redisTemplate.opsForValue().set(lockKey,0);
throw new BusinessException("库存不足!无法操作");
}
因为我们上锁就需要释放锁。但是程序在中途处理业务是发生异常导致没有走到释放锁的步骤。这个时候就导致我们的分布式锁一直被锁。俗称【死锁】。为了避免这种场景的发生。我们常常在上锁的时候给一个有效期。有效期已过自动释放锁。这个特性恰好和redis的过期策略不摩尔和。
上述提及工具
RedisLock
public Boolean tryGetLock(String key , String value) {
return tryGetLock(key, value, -1, TimeUnit.DAYS);
}
public Boolean tryGetLock(String key , String value, Integer expire) {
return tryGetLock(key, value, expire, TimeUnit.SECONDS);
}
public Boolean tryGetLock(String key , String value, Integer expire , TimeUnit timeUnit) {
ValueOperations operations = redisTemplate.opsForValue();
if (operations.setIfAbsent(key, value)) {
//说明 redis没有该key , 换言之 加锁成功 设置过期时间防止死锁
if (expire > 0) {
redisTemplate.expire(key, expire, timeUnit);
}
return true;
}
return false;
}
public Boolean unLock(String key) {
return redisTemplate.delete(key);
}
StockKeyGenerator
@Component()
@Primary
public class StockKeyGenerator implements CacheKeyGenerator {
@Override
public String getLockKey(ProceedingJoinPoint pjp) {
//获取方法签名
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
//获取方法cacheLock注解
StockLock stockLock = method.getAnnotation(StockLock.class);
//获取方法参数
Object[] args = pjp.getArgs();
Parameter[] parameters = method.getParameters();
StringBuilder builder = new StringBuilder();
for (int i = 0; i < parameters.length; i++) {
StockParam stockParam = parameters[i].getAnnotation(StockParam.class);
Object arg = args[i];
if (arg instanceof Map) {
Map<String, Object> temArgMap = (Map<String, Object>) arg;
String[] names = stockParam.names();
for (String name : names) {
if (builder.length() > 0) {
builder.append(stockLock.delimiter());
}
builder.append(temArgMap.get(name));
}
}
}
return builder.toString();
}
}










