129 lines
3.8 KiB
C#
129 lines
3.8 KiB
C#
using LiveForum.Code.Redis.Contract;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace LiveForum.Code.SystemCache
|
|
{
|
|
/// <summary>
|
|
/// 系统缓存服务基类(用于底层支持需要的系统级缓存)
|
|
/// </summary>
|
|
/// <typeparam name="TValue">缓存值类型</typeparam>
|
|
/// <typeparam name="TKey">键类型(用于从缓存值中提取键)</typeparam>
|
|
public abstract class SystemCacheServiceBase<TValue, TKey> : ISystemCacheService<TValue>
|
|
where TKey : notnull
|
|
{
|
|
protected readonly IRedisService _redisService;
|
|
protected abstract string CacheKey { get; }
|
|
protected abstract TimeSpan CacheExpiration { get; }
|
|
|
|
protected SystemCacheServiceBase(IRedisService redisService)
|
|
{
|
|
_redisService = redisService;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 从缓存值中提取键(子类需要实现)
|
|
/// </summary>
|
|
/// <param name="value">缓存值</param>
|
|
/// <returns>键</returns>
|
|
protected abstract TKey GetKeyFromValue(TValue value);
|
|
|
|
/// <summary>
|
|
/// 从数据库加载所有数据(子类需要实现)
|
|
/// </summary>
|
|
/// <returns>数据列表</returns>
|
|
protected abstract Task<List<TValue>> LoadFromDatabaseAsync();
|
|
|
|
/// <summary>
|
|
/// 获取所有缓存数据(从缓存或数据库加载)
|
|
/// </summary>
|
|
public virtual async Task<List<TValue>> GetAllAsync()
|
|
{
|
|
try
|
|
{
|
|
// 先从缓存获取
|
|
var cachedData = await _redisService.GetAsync<List<TValue>>(CacheKey);
|
|
if (cachedData != null && cachedData.Any())
|
|
{
|
|
return cachedData;
|
|
}
|
|
|
|
// 缓存未命中,从数据库加载
|
|
var data = await LoadFromDatabaseAsync();
|
|
if (data != null && data.Any())
|
|
{
|
|
// 写入缓存
|
|
await _redisService.SetAsync(CacheKey, data, CacheExpiration);
|
|
}
|
|
|
|
return data ?? new List<TValue>();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// 记录错误但不抛出异常,尝试从数据库加载
|
|
// 可以在这里添加日志记录
|
|
return await LoadFromDatabaseAsync() ?? new List<TValue>();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 根据键获取缓存数据
|
|
/// </summary>
|
|
public virtual async Task<TValue> GetByKeyAsync(object key)
|
|
{
|
|
if (key == null)
|
|
{
|
|
return default(TValue);
|
|
}
|
|
|
|
var allData = await GetAllAsync();
|
|
TKey keyValue;
|
|
|
|
if (key is TKey directKey)
|
|
{
|
|
keyValue = directKey;
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
keyValue = (TKey)Convert.ChangeType(key, typeof(TKey));
|
|
}
|
|
catch
|
|
{
|
|
return default(TValue);
|
|
}
|
|
}
|
|
|
|
return allData.FirstOrDefault(x => GetKeyFromValue(x).Equals(keyValue));
|
|
}
|
|
|
|
/// <summary>
|
|
/// 清除缓存
|
|
/// </summary>
|
|
public virtual async Task ClearCacheAsync()
|
|
{
|
|
try
|
|
{
|
|
await _redisService.RemoveAsync(CacheKey);
|
|
}
|
|
catch
|
|
{
|
|
// 忽略缓存清除错误
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 刷新缓存(清除并重新加载)
|
|
/// </summary>
|
|
public virtual async Task RefreshCacheAsync()
|
|
{
|
|
await ClearCacheAsync();
|
|
await GetAllAsync();
|
|
}
|
|
}
|
|
}
|
|
|