From 8d07a8cf792796379d95c49b4baa9f107c2a85f6 Mon Sep 17 00:00:00 2001 From: qcjxberin <2505111990@qq.com> Date: Tue, 27 May 2025 23:45:50 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=20DbConfigProvider=20?= =?UTF-8?q?=E7=9A=84=E5=B9=B6=E5=8F=91=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在 DbConfigProvider 类中引入了 `_saveLock` 对象,以防止保存操作与定时刷新操作之间的冲突。更新了 `SaveAll` 方法以使用锁定机制,确保在保存配置时不受干扰,并在保存后更新缓存。同时,`DoRefresh` 方法现在使用 `Monitor.TryEnter` 来避免在保存期间阻塞刷新操作,并在检测到配置改变时重新加载配置并更新缓存,确保操作完成后释放锁。 --- XCode/Configuration/DbConfigProvider.cs | 87 +++++++++++++++++-------- 1 file changed, 60 insertions(+), 27 deletions(-) diff --git a/XCode/Configuration/DbConfigProvider.cs b/XCode/Configuration/DbConfigProvider.cs index decd5206f..51c8a4598 100644 --- a/XCode/Configuration/DbConfigProvider.cs +++ b/XCode/Configuration/DbConfigProvider.cs @@ -26,6 +26,9 @@ public class DbConfigProvider : ConfigProvider public Int32 Period { get; set; } = 15; private IDictionary? _cache; + + /// 保存操作锁,防止与定时刷新冲突 + private readonly Object _saveLock = new(); #endregion #region 方法 @@ -215,13 +218,26 @@ public class DbConfigProvider : ConfigProvider /// 保存配置树到数据源 public override Boolean SaveAll() { - var list = Parameter.FindAllByUserID(UserId, Category); - Save(list, Root, null); + lock (_saveLock) + { + XTrace.WriteLine("[{0}/{1}]开始保存配置", Category, UserId); - // 通知绑定对象,配置数据有改变 - NotifyChange(); + var list = Parameter.FindAllByUserID(UserId, Category); + Save(list, Root, null); - return true; + // 重新加载配置以更新缓存,避免被DoRefresh覆盖 + var dic = GetAll(); + if (dic != null) + { + SaveCache(dic); + XTrace.WriteLine("[{0}/{1}]配置保存完成,已更新缓存", Category, UserId); + } + + // 通知绑定对象,配置数据有改变 + NotifyChange(); + + return true; + } } void Save(IList list, IConfigSection root, String? prefix) @@ -253,6 +269,9 @@ public class DbConfigProvider : ConfigProvider pi.Save(); } } + + // 确保所有数据库操作完成,避免事务延迟导致的读取不一致 + Thread.Sleep(10); } #endregion @@ -290,35 +309,49 @@ public class DbConfigProvider : ConfigProvider /// protected void DoRefresh(Object state) { - using var showSql = Parameter.Meta.Session.Dal.Session.SetShowSql(false); - - var dic = GetAll(); - if (dic == null) return; - - var changed = new Dictionary(); - if (_cache != null) + // 使用TryEnter避免在保存操作期间阻塞 + if (!Monitor.TryEnter(_saveLock, 100)) { - foreach (var item in dic) - { - // 跳过备注 - if (item.Key[0] == '#') continue; - if (!_cache.TryGetValue(item.Key, out var v) || v + "" != item.Value + "") - { - changed.Add(item.Key, item.Value); - } - } + // 如果无法获取锁,说明正在保存,跳过本次刷新 + return; } - if (changed.Count > 0) + try { - XTrace.WriteLine("[{0}/{1}]配置改变,重新加载如下键:{2}", Category, UserId, changed.ToJson()); + using var showSql = Parameter.Meta.Session.Dal.Session.SetShowSql(false); - Root = Build(dic); + var dic = GetAll(); + if (dic == null) return; - // 缓存 - SaveCache(dic); + var changed = new Dictionary(); + if (_cache != null) + { + foreach (var item in dic) + { + // 跳过备注 + if (item.Key[0] == '#') continue; + if (!_cache.TryGetValue(item.Key, out var v) || v + "" != item.Value + "") + { + changed.Add(item.Key, item.Value); + } + } + } - NotifyChange(); + if (changed.Count > 0) + { + XTrace.WriteLine("[{0}/{1}]定时检测到配置改变,重新加载如下键:{2}", Category, UserId, changed.ToJson()); + + Root = Build(dic); + + // 缓存 + SaveCache(dic); + + NotifyChange(); + } + } + finally + { + Monitor.Exit(_saveLock); } } #endregion