core下多租户不生效问题 返回

SqlSugar 沟通中
5 522
该叫什么 彩虹 发布于2025/7/31
悬赏:0 飞吻

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,这是回复,确认只能这样吗,还是代码写的不对QQ截图20250731102327.png

热忱回答5

  • fate sta fate sta VIP0
    2025/7/31

    image.png


    不需要你写什么lock,本身就是跨上下文不共享的。 ADD后只能在当前上下文GET到

    0 回复
  • 彩虹 彩虹 VIP0
    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;
            // 👇 缓存 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 fate sta VIP0
    2025/7/31

    只要有到LOCK都是错误用法

    0 回复
  • fate sta fate sta VIP0
    2025/7/31

    建议直接复制SAAS分库用法

    0 回复
  • fate sta fate sta VIP0
    2025/7/31

    _tenantManager 自身不共享的。加lock是多余 的

    0 回复