core下多租户不生效问题 返回
彩虹 发布于2025/7/31
using Microsoft.Extensions.Options;
using SqlSugar;
namespace ZhiLianMa.Commons.SqlSugar
{
// 定义接口
public interface ISqlSugarClientProvider
{
ISqlSugarClient GetClientForAppId(int appId);
}
public class SqlSugarClientProvider : ISqlSugarClientProvider, IDisposable
{
private readonly string _publicDbConnectionString;
private readonly SqlSugarScope _sqlSugarScope; // 使用 SqlSugarScope 管理所有连接
private readonly object _lockObj = new object(); // 用于线程安全的锁
public SqlSugarClientProvider(IOptions<AppSettings> appSettings)
{
Console.WriteLine("SqlSugarClientProvider 构造函数被调用");
_publicDbConnectionString = appSettings.Value.PublicDB ?? throw new InvalidOperationException("PublicDB connection string is required.");
// 初始化 SqlSugarScope,先添加主库连接 (AppId=0)
_sqlSugarScope = new SqlSugarScope(new List<ConnectionConfig>
{
new ConnectionConfig
{
ConfigId = "public",
ConnectionString = _publicDbConnectionString,
DbType = DbType.SqlServer,
IsAutoCloseConnection = true,
InitKeyType = InitKeyType.Attribute,
MoreSettings = new ConnMoreSettings()
{
IsWithNoLockQuery = true,
DisableNvarchar = true
}
}
});
}
public ISqlSugarClient GetClientForAppId(int appId)
{
string configId = appId == 0 ? "public" : appId.ToString();
Console.WriteLine($"GetClientForAppId: appId={appId}, configId={configId}");
bool exists = _sqlSugarScope.AsTenant().IsAnyConnection(configId);
Console.WriteLine($"configId={configId} 是否已存在: {exists}");
// 检查 SqlSugarScope 是否已存在该连接
if (_sqlSugarScope.AsTenant().IsAnyConnection(configId))
{
return _sqlSugarScope.AsTenant().GetConnectionScope(configId);
}
// 如果不存在,需要添加 (线程安全)
lock (_lockObj)
{
// 再次检查,防止并发下重复添加
if (!_sqlSugarScope.AsTenant().IsAnyConnection(configId))
{
string connectionString = appId == 0
? _publicDbConnectionString
: _publicDbConnectionString.Replace("2ID_Public", $"PDM_{appId}");
var newConfig = new ConnectionConfig
{
ConfigId = configId,
ConnectionString = connectionString,
DbType = DbType.SqlServer,
IsAutoCloseConnection = true,
InitKeyType = InitKeyType.Attribute,
MoreSettings = new ConnMoreSettings()
{
IsWithNoLockQuery = true,
DisableNvarchar = true
}
};
_sqlSugarScope.AsTenant().AddConnection(newConfig);
bool added = _sqlSugarScope.AsTenant().IsAnyConnection(configId);
Console.WriteLine($"AddConnection后 configId={configId} 是否已存在: {added}");
}
}
// 返回新添加或已存在的连接
return _sqlSugarScope.AsTenant().GetConnectionScope(configId);
}
// 提供一个方法,让调用者在应用关闭时可以释放资源
public void Dispose()
{
_sqlSugarScope?.Dispose();
}
}
}
// 1. 注册 UserAuthorize 为 Scoped
builder.Services.AddScoped<UserAuthorize>();
// 2. 注册 ISqlSugarClientProvider
builder.Services.AddSingleton<ISqlSugarClientProvider, SqlSugarClientProvider>();
// 3. 注册非泛型的 ISqlSugarHelper
builder.Services.AddScoped<ISqlSugarHelper, SqlSugarHelper>();
下面是控制台打印的日志
SqlSugarClientProvider 构造函数被调用
GetClientForAppId: appId=10001, configId=10001
configId=10001 是否已存在: False
AddConnection后 configId=10001 是否已存在: True
安全警告:协商的 TLS 1.0 是非安全协议,只有在为了实现向后兼容性才受支持。建议的协议版本为 TLS 1.2 及更高版本。
GetClientForAppId: appId=10001, configId=10001
configId=10001 是否已存在: False
AddConnection后 configId=10001 是否已存在: True
GetClientForAppId: appId=10001, configId=10001
configId=10001 是否已存在: False
AddConnection后 configId=10001 是否已存在: True
GetClientForAppId: appId=10001, configId=10001
configId=10001 是否已存在: False
AddConnection后 configId=10001 是否已存在: True
问题,为什么没有走缓存的,而是,每一次都是新增
if (_sqlSugarScope.AsTenant().IsAnyConnection(configId))
{
return _sqlSugarScope.AsTenant().GetConnectionScope(configId);
}
问了AI,这是回复,确认只能这样吗,还是代码写的不对
热忱回答(5)
-
fate sta VIP0
2025/7/31
不需要你写什么lock,本身就是跨上下文不共享的。 ADD后只能在当前上下文GET到
0 回复 -
彩虹 VIP0
2025/7/31using Microsoft.Extensions.Options; using SqlSugar; namespace ZhiLianMa.Commons.SqlSugar { public interface ISqlSugarClientProvider { ISqlSugarClient GetClientForAppId(int appId); } public class SqlSugarClientProvider : ISqlSugarClientProvider, IDisposable { private readonly string _publicDbConnectionString; private readonly SqlSugarScope _sqlSugarScope; // 👇 缓存 ITenant 实例 (关键修改) private readonly ITenant _tenantManager; private readonly object _lockObj = new object(); public SqlSugarClientProvider(IOptions<AppSettings> appSettings) { Console.WriteLine("SqlSugarClientProvider 构造函数被调用"); _publicDbConnectionString = appSettings.Value.PublicDB ?? throw new InvalidOperationException("PublicDB connection string is required."); // 初始化 SqlSugarScope,添加主库连接 _sqlSugarScope = new SqlSugarScope(new List<ConnectionConfig> { new ConnectionConfig { ConfigId = "public", ConnectionString = _publicDbConnectionString, DbType = DbType.SqlServer, IsAutoCloseConnection = true, InitKeyType = InitKeyType.Attribute, MoreSettings = new ConnMoreSettings() { IsWithNoLockQuery = true, DisableNvarchar = true } } }); // 👇 在构造函数中获取并缓存 ITenant 实例 // 所有后续的 AddConnection, IsAnyConnection, GetConnectionScope 操作都基于此实例 _tenantManager = _sqlSugarScope.AsTenant(); } public ISqlSugarClient GetClientForAppId(int appId) { string configId = appId == 0 ? "public" : appId.ToString(); Console.WriteLine($"GetClientForAppId: appId={appId}, configId={configId}"); // 👇 使用缓存的 _tenantManager 进行检查 bool exists = _tenantManager.IsAnyConnection(configId); Console.WriteLine($"configId={configId} 是否已存在: {exists}"); // 如果连接已存在,直接返回 if (exists) { return _tenantManager.GetConnectionScope(configId); } // 如果不存在,需要添加 (线程安全) lock (_lockObj) { // 双重检查,防止并发下重复添加 if (!_tenantManager.IsAnyConnection(configId)) { // 为非0的appId生成特定的连接字符串 string connectionString = appId == 0 ? _publicDbConnectionString : _publicDbConnectionString.Replace("2ID_Public", $"PDM_{appId}"); var newConfig = new ConnectionConfig { ConfigId = configId, ConnectionString = connectionString, DbType = DbType.SqlServer, IsAutoCloseConnection = true, InitKeyType = InitKeyType.Attribute, MoreSettings = new ConnMoreSettings() { IsWithNoLockQuery = true, DisableNvarchar = true } }; // 👇 使用缓存的 _tenantManager 添加连接 _tenantManager.AddConnection(newConfig); bool added = _tenantManager.IsAnyConnection(configId); Console.WriteLine($"AddConnection后 configId={configId} 是否已存在: {added}"); // 注意:这里added应为true,如果还是false,说明问题可能更深层,但按文档此法应解决 } } // 返回连接 (无论之前是否存在,现在都应存在) return _tenantManager.GetConnectionScope(configId); } // 实现 IDisposable 以正确释放 SqlSugarScope public void Dispose() { _sqlSugarScope?.Dispose(); } } }最终在AI加持下,参考了Saas那篇,AI给出这个,经测试,能实现缓存。大佬,这个做法可行吗
0 回复 -
fate sta VIP0
2025/7/31只要有到LOCK都是错误用法
0 回复 -
fate sta VIP0
2025/7/31建议直接复制SAAS分库用法
0 回复 -
fate sta VIP0
2025/7/31_tenantManager 自身不共享的。加lock是多余 的
0 回复