完善Redis缓存封装
This commit is contained in:
parent
f6130e1d0b
commit
cf9bf6c210
@ -730,7 +730,7 @@ namespace JiShe.CollectBus.IoTDB.Provider
|
|||||||
object rawValue = item1Member.Getter(obj);
|
object rawValue = item1Member.Getter(obj);
|
||||||
string value = rawValue?.ToString();
|
string value = rawValue?.ToString();
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(value))
|
if (!string.IsNullOrWhiteSpace(value))
|
||||||
{
|
{
|
||||||
// 规则1: 严格检查ASCII字母和数字(0-9, A-Z, a-z)
|
// 规则1: 严格检查ASCII字母和数字(0-9, A-Z, a-z)
|
||||||
bool hasInvalidChars = value.Any(c =>
|
bool hasInvalidChars = value.Any(c =>
|
||||||
|
|||||||
@ -123,7 +123,7 @@ namespace JiShe.CollectBus.Application.Contracts
|
|||||||
/// <param name="lastMember">最后一个唯一标识</param>
|
/// <param name="lastMember">最后一个唯一标识</param>
|
||||||
/// <param name="descending">排序方式</param>
|
/// <param name="descending">排序方式</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<BusCacheGlobalPagedResult<T>> GetPagedData<T>(
|
Task<BusCacheGlobalPagedResult<T>> GetSingleData<T>(
|
||||||
string redisHashCacheKey,
|
string redisHashCacheKey,
|
||||||
string redisZSetScoresIndexCacheKey,
|
string redisZSetScoresIndexCacheKey,
|
||||||
string scoreValueRawData,
|
string scoreValueRawData,
|
||||||
|
|||||||
@ -42,8 +42,6 @@ namespace JiShe.CollectBus.RedisDataCache
|
|||||||
Instance = _freeRedisProvider.Instance;
|
Instance = _freeRedisProvider.Instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
//todo 单个数据查询
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 单个添加数据
|
/// 单个添加数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -370,7 +368,7 @@ namespace JiShe.CollectBus.RedisDataCache
|
|||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 通过集中器与表计信息排序索引获取数据
|
/// 通过集中器与表计信息排序索引获取单个数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T"></typeparam>
|
/// <typeparam name="T"></typeparam>
|
||||||
/// <param name="redisHashCacheKey">主数据存储Hash缓存Key</param>
|
/// <param name="redisHashCacheKey">主数据存储Hash缓存Key</param>
|
||||||
@ -381,24 +379,105 @@ namespace JiShe.CollectBus.RedisDataCache
|
|||||||
/// <param name="lastMember">最后一个唯一标识</param>
|
/// <param name="lastMember">最后一个唯一标识</param>
|
||||||
/// <param name="descending">排序方式</param>
|
/// <param name="descending">排序方式</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<BusCacheGlobalPagedResult<T>> GetPagedData<T>(
|
public async Task<BusCacheGlobalPagedResult<T>> GetSingleData<T>(
|
||||||
string redisHashCacheKey,
|
string redisHashCacheKey,
|
||||||
string redisZSetScoresIndexCacheKey,
|
string redisZSetScoresIndexCacheKey,
|
||||||
string scoreValueRawData,
|
string scoreValueRawData,
|
||||||
int pageSize = 10,
|
int pageSize = 10,
|
||||||
decimal? lastScore = null,
|
decimal? lastScore = null,
|
||||||
string lastMember = null,
|
string lastMember = null,
|
||||||
bool descending = true)
|
bool descending = true)
|
||||||
where T : DeviceCacheBasicModel
|
where T : DeviceCacheBasicModel
|
||||||
{
|
{
|
||||||
var rawDataArray = scoreValueRawData.Split(":");
|
// 参数校验
|
||||||
string focusAddress = rawDataArray[0];
|
if (string.IsNullOrWhiteSpace(redisHashCacheKey) ||
|
||||||
string point = rawDataArray[1];
|
string.IsNullOrWhiteSpace(redisZSetScoresIndexCacheKey) ||
|
||||||
|
string.IsNullOrWhiteSpace(scoreValueRawData))
|
||||||
|
{
|
||||||
|
_logger.LogError($"{nameof(GetSingleData)} 参数异常,-101");
|
||||||
|
return new BusCacheGlobalPagedResult<T> { Items = new List<T>() };
|
||||||
|
}
|
||||||
|
|
||||||
long scoreValue = 0;
|
// 解析原始数据
|
||||||
|
var rawDataArray = scoreValueRawData.Split(':');
|
||||||
|
if (rawDataArray.Length != 2)
|
||||||
|
{
|
||||||
|
_logger.LogError($"{nameof(GetSingleData)} scoreValueRawData格式错误,应为[focusAddress:point]");
|
||||||
|
return new BusCacheGlobalPagedResult<T> { Items = new List<T>() };
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算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<T> { Items = new List<T>() };
|
||||||
|
}
|
||||||
|
|
||||||
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<T> { Items = new List<T>() };
|
||||||
|
|
||||||
|
// 解析Redis返回数据
|
||||||
|
var resultArray = (object[])result;
|
||||||
|
var memberId = (string)resultArray[0];
|
||||||
|
var dataStr = (string)resultArray[1];
|
||||||
|
|
||||||
|
// 反序列化数据
|
||||||
|
var data = BusJsonSerializer.Deserialize<T>(dataStr);
|
||||||
|
if (data == null)
|
||||||
|
{
|
||||||
|
_logger.LogError($"{nameof(GetSingleData)} 反序列化失败,MemberId: {memberId}");
|
||||||
|
return new BusCacheGlobalPagedResult<T> { Items = new List<T>() };
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构造返回结果
|
||||||
|
return new BusCacheGlobalPagedResult<T>
|
||||||
|
{
|
||||||
|
Items = new List<T> { data },
|
||||||
|
TotalCount = 1,
|
||||||
|
PageSize = 1,
|
||||||
|
HasNext = false,
|
||||||
|
NextScore = null,
|
||||||
|
NextMember = null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, $"{nameof(GetSingleData)} Redis操作异常");
|
||||||
|
return new BusCacheGlobalPagedResult<T> { Items = new List<T>() };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -559,67 +638,7 @@ namespace JiShe.CollectBus.RedisDataCache
|
|||||||
PageSize = pageSize,
|
PageSize = pageSize,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
///// <summary>
|
|
||||||
///// 通过集中器与表计信息排序索引获取数据
|
|
||||||
///// </summary>
|
|
||||||
///// <typeparam name="T"></typeparam>
|
|
||||||
///// <param name="redisHashCacheKey">主数据存储Hash缓存Key</param>
|
|
||||||
///// <param name="redisZSetScoresIndexCacheKey">ZSET索引缓存Key</param>
|
|
||||||
///// <param name="pageSize">分页尺寸</param>
|
|
||||||
///// <param name="lastScore">最后一个索引</param>
|
|
||||||
///// <param name="lastMember">最后一个唯一标识</param>
|
|
||||||
///// <param name="descending">排序方式</param>
|
|
||||||
///// <returns></returns>
|
|
||||||
//public async Task<BusCacheGlobalPagedResult<T>> GetAllPagedData<T>(
|
|
||||||
//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<T>(redisHashCacheKey, pageResult.Members);
|
|
||||||
|
|
||||||
// return new BusCacheGlobalPagedResult<T>
|
|
||||||
// {
|
|
||||||
// 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,
|
|
||||||
// };
|
|
||||||
//}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 游标分页查询
|
/// 游标分页查询
|
||||||
|
|||||||
@ -737,7 +737,7 @@ namespace JiShe.CollectBus.ScheduledMeterReading
|
|||||||
ItemCode = tempItem,
|
ItemCode = tempItem,
|
||||||
DataTimeMark = new Protocol.DataTimeMark()
|
DataTimeMark = new Protocol.DataTimeMark()
|
||||||
{
|
{
|
||||||
Density = ammeterInfo.TimeDensity.GetDensity(),//转换成协议的值
|
Density = ammeterInfo.TimeDensity.GetFocusDensity(),//转换成协议的值
|
||||||
Point = 1,
|
Point = 1,
|
||||||
DataTime = timestamps,
|
DataTime = timestamps,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,7 +20,7 @@ namespace JiShe.CollectBus.IotSystems.Ammeters
|
|||||||
/// ZSet排序索引分数值,具体值可以根据不同业务场景进行定义,例如时间戳
|
/// ZSet排序索引分数值,具体值可以根据不同业务场景进行定义,例如时间戳
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Column(IsIgnore = true)]
|
[Column(IsIgnore = true)]
|
||||||
public override long ScoreValue => ((long)FocusId << 32) | (uint)DateTime.Now.Ticks;
|
public override long ScoreValue => Common.Helpers.CommonHelper.GetFocusScores(FocusAddress,MeteringCode);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 电表名称
|
/// 电表名称
|
||||||
|
|||||||
@ -10,6 +10,8 @@ using System.Text;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using JiShe.CollectBus.Common.Attributes;
|
using JiShe.CollectBus.Common.Attributes;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
|
using JiShe.CollectBus.Common.Enums;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
namespace JiShe.CollectBus.Common.Helpers
|
namespace JiShe.CollectBus.Common.Helpers
|
||||||
{
|
{
|
||||||
@ -796,7 +798,7 @@ namespace JiShe.CollectBus.Common.Helpers
|
|||||||
/// <param name="msa"></param>
|
/// <param name="msa"></param>
|
||||||
/// <param name="seq"></param>
|
/// <param name="seq"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
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')}";
|
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
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 采集频率转换为集中器采集密度
|
/// 系统采集频率转换为集中器采集密度
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="timeDensity"></param>
|
/// <param name="timeDensity"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static int GetDensity(this int timeDensity) =>
|
public static int GetFocusDensity(this int timeDensity) => timeDensity switch
|
||||||
timeDensity switch
|
{
|
||||||
{
|
0 => 0,//无
|
||||||
0 => 0,//无
|
1 => 255,//1分钟
|
||||||
1 => 255,//1分钟
|
5 => 245,//5分钟
|
||||||
5 => 245,//5分钟
|
15 => 1,//15分钟
|
||||||
15 => 1,//15分钟
|
30 => 2,//30分钟
|
||||||
30 => 2,//30分钟
|
60 => 3,//60分钟
|
||||||
60 => 3,//60分钟
|
_ => -1//采集项本身无密度位
|
||||||
_ => -1//采集项本身无密度位
|
};
|
||||||
};
|
|
||||||
|
/// <summary>
|
||||||
|
/// 集中器采集密度转换为系统采集频率
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="density"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
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//采集项本身无密度位
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取集中器ZSet Scores
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="focusScores"></param>
|
||||||
|
/// <param name="point"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user