redis 业务锁 not exist 模式
阅读原文时间:2023年07月14日阅读:1

业务核心模块只能提交一次,原实现方案 前端加提交限制、后端加数据库业务逻辑判定,结果失效,api站点部署多台负载,切方法需要强求第三方接口 响应时间较慢 ,故放弃lock。

解决方案:redis业务锁。

1:利用redis原子性解决并发问题

2:利用redis集群署解决分布式部署问题

3:利用redis性能快解决时间消耗问题

4:利用redis过期时间解决死锁问题

5:利用rediskey唯一性解决互斥问题

问题:超时时间存在误差

2.1:RedisManager 中重构Set,可以设置When 属性,Always 总是保存,Exists 存在时保存,NotExists 不存在时保存。返回值中true与false代表是否操作。

设置notExists模式可以判定redis中是否存在值

public static bool Set(string key, T objectValue, long lNumofSeconds = , StackExchange.Redis.When when =When.Always)
{
if (!Enum.IsDefined(typeof(When), when))
throw new InvalidEnumArgumentException(nameof(when), (int) when, typeof(When));
bool result = false;
try
{
key = redisConfigInfo.KeySuffix + key;
if (lNumofSeconds > 0L)
{
return ManagerMaster.GetDatabase(-, null).StringSet(key, ConvertJson(objectValue), new TimeSpan?(TimeSpan.FromSeconds((double)lNumofSeconds)), when, CommandFlags.None);
}
return ManagerMaster.GetDatabase(-, null).StringSet(key, ConvertJson(objectValue), null, when, CommandFlags.None);
}
catch (Exception) { result = false; }
return result;
}

namespace StackExchange.Redis
{
public enum When
{
Always,
Exists,
NotExists,
}
}

2.2:判定是否存在redis缓存 ,如果存在则返回true 如果不存在就返回false并保存值

///

/// 判定缓存是否存在 /// 不存在就添加缓存 ///
///
/// redis值
/// 过期时间/秒
/// {0:cache;2=redis};默认redis
/// true 代表存在redis false 代表不存在redis 自动写入
public static bool CheckRedisNoExistSet(string redisKey, string inputValue, int timeSecond = ,int cacheType=)
{
//redis写 NX-- Only set the key if it does not already exist.
//true写成功 无数据 写入,false 没写 或者异常
return !RedisManager.Set(redisKey, inputValue, timeSecond, When.NotExists);
}

通过redis 来实现业务锁功能

1:最小单位可是精确到某一个表的ID ,例如:reportID

2:如果正在处理这个案件则阻止其他并发操作

3:自动过期时间为120秒,方法执行完毕自动释放

///

/// 正式全部提交 /// 1.返回code=0表示存在重复案件 /// 2.首次IsContinue传0,继续提交IsContinue传1 ///
///
///
[HttpPost, Log("全部提交")]
public BaseResponse CenterSubmitAllSimpleCase([FromBody]CenterSubmitAllSimpleCaseRequest request)
{
var redisKey = string.Format(ConfigurationManager.AppSettings["CenterSubmitAllSimpleCase"], request.ReportId.ToString());
if (CacheProvider.CheckRedisNoExistSet(redisKey, request.ReportId.ToString()))
{
return BaseResponse.GetBaseResponse(BusinessStatusType.Failed, "请勿重复提交");
}
var centerFlow = _centerFlowService.QueryCenterFlowByReportId(request.ReportId).Any(e => e.Status == (int)SubmitCenterStatus.提交中);
if (centerFlow)
return BaseResponse.GetBaseResponse(BusinessStatusType.Failed, "请勿重复提交");
request.CenterSubmitType = CenterSubmitType.全部提交;
BaseResponse result = _callBackService.SubmitCompleteToCenter(request);
CacheProvider.Remove(redisKey);
return result;
}