From cf9bf6c210687638d0872fb0c3b40ca43d75f3f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E7=9B=8A?= Date: Sun, 11 May 2025 21:53:55 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84Redis=E7=BC=93=E5=AD=98?= =?UTF-8?q?=E5=B0=81=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Provider/IoTDBProvider.cs | 2 +- .../RedisDataCache/IRedisDataCacheService.cs | 2 +- .../RedisDataCache/RedisDataCacheService.cs | 175 ++++++++++-------- .../BasicScheduledMeterReadingService.cs | 2 +- .../IotSystems/Ammeters/AmmeterInfo.cs | 2 +- .../Helpers/CommonHelper.cs | 61 ++++-- 6 files changed, 149 insertions(+), 95 deletions(-) diff --git a/modules/JiShe.CollectBus.IoTDB/Provider/IoTDBProvider.cs b/modules/JiShe.CollectBus.IoTDB/Provider/IoTDBProvider.cs index 34b4f4b..dfe442d 100644 --- a/modules/JiShe.CollectBus.IoTDB/Provider/IoTDBProvider.cs +++ b/modules/JiShe.CollectBus.IoTDB/Provider/IoTDBProvider.cs @@ -730,7 +730,7 @@ namespace JiShe.CollectBus.IoTDB.Provider object rawValue = item1Member.Getter(obj); string value = rawValue?.ToString(); - if (!string.IsNullOrEmpty(value)) + if (!string.IsNullOrWhiteSpace(value)) { // 规则1: 严格检查ASCII字母和数字(0-9, A-Z, a-z) bool hasInvalidChars = value.Any(c => diff --git a/services/JiShe.CollectBus.Application.Contracts/RedisDataCache/IRedisDataCacheService.cs b/services/JiShe.CollectBus.Application.Contracts/RedisDataCache/IRedisDataCacheService.cs index dc7c14e..b5f492c 100644 --- a/services/JiShe.CollectBus.Application.Contracts/RedisDataCache/IRedisDataCacheService.cs +++ b/services/JiShe.CollectBus.Application.Contracts/RedisDataCache/IRedisDataCacheService.cs @@ -123,7 +123,7 @@ namespace JiShe.CollectBus.Application.Contracts /// 最后一个唯一标识 /// 排序方式 /// - Task> GetPagedData( + Task> GetSingleData( string redisHashCacheKey, string redisZSetScoresIndexCacheKey, string scoreValueRawData, diff --git a/services/JiShe.CollectBus.Application/RedisDataCache/RedisDataCacheService.cs b/services/JiShe.CollectBus.Application/RedisDataCache/RedisDataCacheService.cs index e413527..ebf1d2b 100644 --- a/services/JiShe.CollectBus.Application/RedisDataCache/RedisDataCacheService.cs +++ b/services/JiShe.CollectBus.Application/RedisDataCache/RedisDataCacheService.cs @@ -42,8 +42,6 @@ namespace JiShe.CollectBus.RedisDataCache Instance = _freeRedisProvider.Instance; } - //todo 单个数据查询 - /// /// 单个添加数据 /// @@ -370,7 +368,7 @@ namespace JiShe.CollectBus.RedisDataCache /// - /// 通过集中器与表计信息排序索引获取数据 + /// 通过集中器与表计信息排序索引获取单个数据 /// /// /// 主数据存储Hash缓存Key @@ -381,24 +379,105 @@ namespace JiShe.CollectBus.RedisDataCache /// 最后一个唯一标识 /// 排序方式 /// - public async Task> GetPagedData( - string redisHashCacheKey, - string redisZSetScoresIndexCacheKey, - string scoreValueRawData, - int pageSize = 10, - decimal? lastScore = null, - string lastMember = null, - bool descending = true) - where T : DeviceCacheBasicModel + public async Task> GetSingleData( + string redisHashCacheKey, + string redisZSetScoresIndexCacheKey, + string scoreValueRawData, + int pageSize = 10, + decimal? lastScore = null, + string lastMember = null, + bool descending = true) + where T : DeviceCacheBasicModel { - var rawDataArray = scoreValueRawData.Split(":"); - string focusAddress = rawDataArray[0]; - string point = rawDataArray[1]; + // 参数校验 + if (string.IsNullOrWhiteSpace(redisHashCacheKey) || + string.IsNullOrWhiteSpace(redisZSetScoresIndexCacheKey) || + string.IsNullOrWhiteSpace(scoreValueRawData)) + { + _logger.LogError($"{nameof(GetSingleData)} 参数异常,-101"); + return new BusCacheGlobalPagedResult { Items = new List() }; + } - long scoreValue = 0; + // 解析原始数据 + var rawDataArray = scoreValueRawData.Split(':'); + if (rawDataArray.Length != 2) + { + _logger.LogError($"{nameof(GetSingleData)} scoreValueRawData格式错误,应为[focusAddress:point]"); + return new BusCacheGlobalPagedResult { Items = new List() }; + } + // 计算Score值 + long scoreValue; + try + { + var focusAddress = rawDataArray[0]; + var point = Convert.ToInt32(rawDataArray[1]); + scoreValue = CommonHelper.GetFocusScores(focusAddress, point); + } + catch (Exception ex) + { + _logger.LogError(ex, $"{nameof(GetSingleData)} 计算Score值失败"); + return new BusCacheGlobalPagedResult { Items = new List() }; + } - throw new Exception(); + // Lua脚本:原子化查询操作 + const string luaScript = @" + local zsetKey = KEYS[1] + local hashKey = KEYS[2] + local targetScore = ARGV[1] + + -- 精确匹配Score并获取第一个成员 + local members = redis.call('ZRANGEBYSCORE', zsetKey, targetScore, targetScore, 'LIMIT', 0, 1) + if #members == 0 then + return nil + end + + -- 获取哈希表数据 + local member = members[1] + local data = redis.call('HGET', hashKey, member) + return {member, data}"; + + try + { + // 执行脚本 + var result = await Instance.EvalAsync( + luaScript, + new[] { redisZSetScoresIndexCacheKey, redisHashCacheKey }, + new object[] { scoreValue }); + + // 处理空结果 + if (result == null) + return new BusCacheGlobalPagedResult { Items = new List() }; + + // 解析Redis返回数据 + var resultArray = (object[])result; + var memberId = (string)resultArray[0]; + var dataStr = (string)resultArray[1]; + + // 反序列化数据 + var data = BusJsonSerializer.Deserialize(dataStr); + if (data == null) + { + _logger.LogError($"{nameof(GetSingleData)} 反序列化失败,MemberId: {memberId}"); + return new BusCacheGlobalPagedResult { Items = new List() }; + } + + // 构造返回结果 + return new BusCacheGlobalPagedResult + { + Items = new List { data }, + TotalCount = 1, + PageSize = 1, + HasNext = false, + NextScore = null, + NextMember = null + }; + } + catch (Exception ex) + { + _logger.LogError(ex, $"{nameof(GetSingleData)} Redis操作异常"); + return new BusCacheGlobalPagedResult { Items = new List() }; + } } /// @@ -559,67 +638,7 @@ namespace JiShe.CollectBus.RedisDataCache PageSize = pageSize, }; } - - ///// - ///// 通过集中器与表计信息排序索引获取数据 - ///// - ///// - ///// 主数据存储Hash缓存Key - ///// ZSET索引缓存Key - ///// 分页尺寸 - ///// 最后一个索引 - ///// 最后一个唯一标识 - ///// 排序方式 - ///// - //public async Task> GetAllPagedData( - //string redisHashCacheKey, - //string redisZSetScoresIndexCacheKey, - //int pageSize = 1000, - //decimal? lastScore = null, - //string lastMember = null, - //bool descending = true) - //where T : DeviceCacheBasicModel - //{ - // // 参数校验增强 - // if (string.IsNullOrWhiteSpace(redisHashCacheKey) || string.IsNullOrWhiteSpace(redisZSetScoresIndexCacheKey)) - // { - // _logger.LogError($"{nameof(GetAllPagedData)} 参数异常,-101"); - // return null; - // } - - // if (pageSize < 1 || pageSize > 10000) - // { - // _logger.LogError($"{nameof(GetAllPagedData)} 分页大小应在1-10000之间,-102"); - // return null; - // } - - // //// 分页参数解析 - // //var (startScore, excludeMember) = descending - // // ? (lastScore ?? decimal.MaxValue, lastMember) - // // : (lastScore ?? 0, lastMember); - - // //执行分页查询(整合游标处理) - // var pageResult = await GetPagedMembers( - // redisZSetScoresIndexCacheKey, - // pageSize, - // lastScore, - // lastMember, - // descending); - - // // 批量获取数据(优化内存分配) - // var dataDict = await BatchGetData(redisHashCacheKey, pageResult.Members); - - // return new BusCacheGlobalPagedResult - // { - // Items = pageResult.Members.Select(m => dataDict.TryGetValue(m, out var v) ? v : default) - // .Where(x => x != null).ToList(), - // HasNext = pageResult.HasNext, - // NextScore = pageResult.NextScore, - // NextMember = pageResult.NextMember, - // TotalCount = await GetTotalCount(redisZSetScoresIndexCacheKey), - // PageSize = pageSize, - // }; - //} + /// /// 游标分页查询 diff --git a/services/JiShe.CollectBus.Application/ScheduledMeterReading/BasicScheduledMeterReadingService.cs b/services/JiShe.CollectBus.Application/ScheduledMeterReading/BasicScheduledMeterReadingService.cs index 9d45f08..270bb67 100644 --- a/services/JiShe.CollectBus.Application/ScheduledMeterReading/BasicScheduledMeterReadingService.cs +++ b/services/JiShe.CollectBus.Application/ScheduledMeterReading/BasicScheduledMeterReadingService.cs @@ -737,7 +737,7 @@ namespace JiShe.CollectBus.ScheduledMeterReading ItemCode = tempItem, DataTimeMark = new Protocol.DataTimeMark() { - Density = ammeterInfo.TimeDensity.GetDensity(),//转换成协议的值 + Density = ammeterInfo.TimeDensity.GetFocusDensity(),//转换成协议的值 Point = 1, DataTime = timestamps, } diff --git a/services/JiShe.CollectBus.Domain/IotSystems/Ammeters/AmmeterInfo.cs b/services/JiShe.CollectBus.Domain/IotSystems/Ammeters/AmmeterInfo.cs index 60d6c91..4cd69ba 100644 --- a/services/JiShe.CollectBus.Domain/IotSystems/Ammeters/AmmeterInfo.cs +++ b/services/JiShe.CollectBus.Domain/IotSystems/Ammeters/AmmeterInfo.cs @@ -20,7 +20,7 @@ namespace JiShe.CollectBus.IotSystems.Ammeters /// ZSet排序索引分数值,具体值可以根据不同业务场景进行定义,例如时间戳 /// [Column(IsIgnore = true)] - public override long ScoreValue => ((long)FocusId << 32) | (uint)DateTime.Now.Ticks; + public override long ScoreValue => Common.Helpers.CommonHelper.GetFocusScores(FocusAddress,MeteringCode); /// /// 电表名称 diff --git a/shared/JiShe.CollectBus.Common/Helpers/CommonHelper.cs b/shared/JiShe.CollectBus.Common/Helpers/CommonHelper.cs index e3177a1..7d3fc4a 100644 --- a/shared/JiShe.CollectBus.Common/Helpers/CommonHelper.cs +++ b/shared/JiShe.CollectBus.Common/Helpers/CommonHelper.cs @@ -10,6 +10,8 @@ using System.Text; using System.Threading.Tasks; using JiShe.CollectBus.Common.Attributes; using System.Collections.Specialized; +using JiShe.CollectBus.Common.Enums; +using Newtonsoft.Json.Linq; namespace JiShe.CollectBus.Common.Helpers { @@ -796,7 +798,7 @@ namespace JiShe.CollectBus.Common.Helpers /// /// /// - public static string GetTaskMark(int afn, int fn, int pn, int msa,int seq) + public static string GetTaskMark(int afn, int fn, int pn, int msa, int seq) { var makstr = $"{afn.ToString().PadLeft(2, '0')}{fn.ToString().PadLeft(2, '0')}{pn.ToString().PadLeft(2, '0')}{msa.ToString().PadLeft(2, '0')}{seq.ToString().PadLeft(2, '0')}"; @@ -860,20 +862,53 @@ namespace JiShe.CollectBus.Common.Helpers } /// - /// 采集频率转换为集中器采集密度 + /// 系统采集频率转换为集中器采集密度 /// /// /// - public static int GetDensity(this int timeDensity) => - timeDensity switch - { - 0 => 0,//无 - 1 => 255,//1分钟 - 5 => 245,//5分钟 - 15 => 1,//15分钟 - 30 => 2,//30分钟 - 60 => 3,//60分钟 - _ => -1//采集项本身无密度位 - }; + public static int GetFocusDensity(this int timeDensity) => timeDensity switch + { + 0 => 0,//无 + 1 => 255,//1分钟 + 5 => 245,//5分钟 + 15 => 1,//15分钟 + 30 => 2,//30分钟 + 60 => 3,//60分钟 + _ => -1//采集项本身无密度位 + }; + + /// + /// 集中器采集密度转换为系统采集频率 + /// + /// + /// + public static int GetSystemDensity(this int density) => density switch + { + 0 => 0,//无 + 255 => 1,//1分钟 + 245 => 5,//5分钟 + 1 => 15,//15分钟 + 2 => 30,//30分钟 + 3 => 60,//60分钟 + _ => -1//采集项本身无密度位 + }; + + /// + /// 获取集中器ZSet Scores + /// + /// + /// + /// + public static long GetFocusScores(string focusScores, int point) + { + bool hasInvalidChars = focusScores.Any(c => !(c >= '0' && c <= '9')); + if (hasInvalidChars) + { + throw new Exception($"{nameof(GetFocusScores)} 集中器地址格式错误"); + } + var scoresStr = $"{focusScores}{point.ToString().PadLeft(2, '0')}"; + + return Convert.ToInt64(scoresStr); + } } }