DataDepositPool 数据存储池
DataDepositPool 是一个带容量限制的临时数据存储池,适用于需要临时存储和检索数据的场景。
using MiCake.Util.Store;// 默认容量 1000var pool = new DataDepositPool();
// 自定义容量var pool = new DataDepositPool(maxCapacity: 5000);Deposit - 存储数据
Section titled “Deposit - 存储数据”// 存储数据pool.Deposit("user-1", userData);
// 替换已存在的数据pool.Deposit("user-1", newUserData, isReplace: true);参数说明:
key: 数据的唯一标识符value: 要存储的数据对象isReplace: 是否替换已存在的数据(默认 false)
TakeOut - 获取数据
Section titled “TakeOut - 获取数据”// 获取数据(返回 object)object? data = pool.TakeOut("user-1");
// 获取指定类型的数据User? user = pool.TakeOut<User>("user-1");
// 数据不存在时返回 nullvar notFound = pool.TakeOut<User>("not-exists"); // nullTakeOutByType - 按类型获取
Section titled “TakeOutByType - 按类型获取”// 获取指定类型的所有数据List<object> users = pool.TakeOutByType(typeof(User));
// 转换为强类型List<User> typedUsers = users.Cast<User>().ToList();ReleaseAll - 释放所有数据
Section titled “ReleaseAll - 释放所有数据”pool.ReleaseAll();| 属性 | 说明 |
|---|---|
Count | 当前存储的数据数量 |
MaxCapacity | 最大容量 |
临时数据缓存
Section titled “临时数据缓存”public class SessionStore : ISingletonService{ private readonly DataDepositPool _pool = new(maxCapacity: 10000);
public void StoreSession(string sessionId, SessionData data) { _pool.Deposit(sessionId, data, isReplace: true); }
public SessionData? GetSession(string sessionId) { return _pool.TakeOut<SessionData>(sessionId); }
public void RemoveSession(string sessionId) { _pool.TakeOut(sessionId); // 获取并移除 }
public void ClearAllSessions() { _pool.ReleaseAll(); }
public int GetActiveSessionCount() { return _pool.Count; }}中间结果存储
Section titled “中间结果存储”public class BatchProcessor{ private readonly DataDepositPool _resultPool = new();
public async Task ProcessBatchAsync(List<Item> items) { // 并行处理 await Parallel.ForEachAsync(items, async (item, ct) => { var result = await ProcessItemAsync(item); _resultPool.Deposit($"result-{item.Id}", result); }); }
public List<ProcessResult> GetAllResults() { return _resultPool.TakeOutByType(typeof(ProcessResult)) .Cast<ProcessResult>() .ToList(); }
public ProcessResult? GetResult(string itemId) { return _resultPool.TakeOut<ProcessResult>($"result-{itemId}"); }
public void Complete() { _resultPool.ReleaseAll(); _resultPool.Dispose(); }}工作流状态管理
Section titled “工作流状态管理”public class WorkflowEngine{ private readonly DataDepositPool _statePool = new(maxCapacity: 1000);
public void SaveWorkflowState(string workflowId, WorkflowState state) { try { _statePool.Deposit(workflowId, state, isReplace: true); } catch (InvalidOperationException ex) when (ex.Message.Contains("capacity")) { // 容量不足,清理旧状态 CleanupOldStates(); _statePool.Deposit(workflowId, state, isReplace: true); } }
public WorkflowState? LoadWorkflowState(string workflowId) { return _statePool.TakeOut<WorkflowState>(workflowId); }
public List<WorkflowState> GetAllActiveWorkflows() { return _statePool.TakeOutByType(typeof(WorkflowState)) .Cast<WorkflowState>() .Where(s => s.IsActive) .ToList(); }
private void CleanupOldStates() { var allStates = _statePool.TakeOutByType(typeof(WorkflowState)) .Cast<WorkflowState>() .ToList();
// 只保留最近的 800 个 var toKeep = allStates .OrderByDescending(s => s.LastModified) .Take(800) .ToList();
_statePool.ReleaseAll();
foreach (var state in toKeep) { _statePool.Deposit(state.WorkflowId, state); } }}请求上下文存储
Section titled “请求上下文存储”public class RequestContextStore{ private readonly DataDepositPool _pool = new();
public void StoreContext(string requestId, RequestContext context) { _pool.Deposit(requestId, context); }
public RequestContext? GetContext(string requestId) { return _pool.TakeOut<RequestContext>(requestId); }
// 在请求结束时清理 public void CleanupRequest(string requestId) { _pool.TakeOut(requestId); }}
// 在中间件中使用public class RequestContextMiddleware{ private readonly RequestContextStore _store;
public async Task InvokeAsync(HttpContext context, RequestDelegate next) { var requestId = Guid.NewGuid().ToString();
_store.StoreContext(requestId, new RequestContext { RequestId = requestId, StartTime = DateTime.UtcNow, UserId = context.User.FindFirst("sub")?.Value });
try { await next(context); } finally { _store.CleanupRequest(requestId); } }}| 场景 | 异常 | 说明 |
|---|---|---|
| key 为 null | ArgumentNullException | 键不能为 null |
| key 已存在且 isReplace = false | InvalidOperationException | 键已存在 |
| 超出容量限制 | InvalidOperationException | 超过最大容量 |
| 已释放后操作 | ObjectDisposedException | 对象已释放 |
异常处理示例
Section titled “异常处理示例”public class SafeDataPool{ private readonly DataDepositPool _pool = new(maxCapacity: 1000);
public bool TryDeposit(string key, object value) { try { _pool.Deposit(key, value); return true; } catch (ArgumentNullException) { _logger.LogError("Key cannot be null"); return false; } catch (InvalidOperationException ex) when (ex.Message.Contains("capacity")) { _logger.LogWarning("Pool capacity exceeded"); return false; } catch (InvalidOperationException ex) when (ex.Message.Contains("already exists")) { _logger.LogInformation("Key already exists, use isReplace=true to update"); return false; } catch (Exception ex) { _logger.LogError(ex, "Unexpected error"); return false; } }}1. 设置合理容量
Section titled “1. 设置合理容量”// ✅ 正确:根据预期数据量设置容量var pool = new DataDepositPool(maxCapacity: EstimateMaxDataItems());
// ❌ 错误:容量过小var pool = new DataDepositPool(maxCapacity: 10); // 容易超限
// ❌ 错误:容量过大var pool = new DataDepositPool(maxCapacity: 1000000); // 占用过多内存2. 及时释放
Section titled “2. 及时释放”// ✅ 正确:使用完毕后释放using (var pool = new DataDepositPool()){ // 使用 pool}
// 或手动释放var pool = new DataDepositPool();try{ // 使用 pool}finally{ pool.Dispose();}3. 使用泛型方法
Section titled “3. 使用泛型方法”// ✅ 正确:使用泛型方法获取强类型数据var user = pool.TakeOut<User>("user-1");
// ❌ 不推荐:需要手动转换object? obj = pool.TakeOut("user-1");var user = obj as User; // 需要额外转换4. 处理容量异常
Section titled “4. 处理容量异常”// ✅ 正确:处理容量超限public void AddData(string key, object value){ try { _pool.Deposit(key, value); } catch (InvalidOperationException ex) when (ex.Message.Contains("capacity")) { // 清理策略 1: 释放所有数据 _pool.ReleaseAll(); _pool.Deposit(key, value);
// 或策略 2: 移除最旧的数据 // RemoveOldestData(); // _pool.Deposit(key, value); }}5. 注册为单例
Section titled “5. 注册为单例”// ✅ 正确:注册为单例public class MyModule : MiCakeModule{ public override void ConfigureServices(ModuleConfigServiceContext context) { context.Services.AddSingleton<DataDepositPool>(sp => new DataDepositPool(maxCapacity: 1000));
base.ConfigureServices(context); }}
// ❌ 错误:注册为瞬时或作用域services.AddScoped<DataDepositPool>(); // 每个请求新实例,失去缓存意义| 操作 | 时间复杂度 | 说明 |
|---|---|---|
Deposit | O(1) | 字典插入 |
TakeOut | O(1) | 字典查找并移除 |
TakeOutByType | O(n) | 需要遍历所有数据 |
ReleaseAll | O(1) | 清空字典 |
性能优化建议
Section titled “性能优化建议”// ✅ 推荐:使用 TakeOut(O(1))var data = pool.TakeOut<User>("user-1");
// ⚠️ 注意:TakeOutByType 性能较差(O(n))var allUsers = pool.TakeOutByType(typeof(User)); // 避免频繁调用- 容量限制:超出容量会抛出异常,需提前处理
- 数据移除:
TakeOut会移除数据,再次获取返回 null - 线程安全:内部使用字典,不保证线程安全,需外部同步
- 内存占用:存储的数据会占用内存,及时释放不需要的数据
- 类型检查:
TakeOutByType使用is进行类型检查
✅ 适合使用
Section titled “✅ 适合使用”- 会话存储
- 中间结果缓存
- 工作流状态管理
- 请求上下文存储
- 临时数据交换
❌ 不适合使用
Section titled “❌ 不适合使用”- 长期数据存储(使用数据库)
- 大对象存储(占用过多内存)
- 需要持久化的数据
- 分布式场景(单机内存)
- 高并发写入(需额外同步)