SqlSugarClient 模式 IOC方式实现线程安全 返回

SqlSugar 沟通中
11 3444


1、SqlSugarClient通过AddScoped注入 (注意 SqlSugarClient才能这么用)

2、代码如下

public class MyProcessor
{
    private readonly IServiceScopeFactory _scopeFactory;

    public MyProcessor(IServiceScopeFactory scopeFactory)
    {
        _scopeFactory = scopeFactory;
    }

    public async Task ProcessBatchAsync(List<int> ids)
    {
        var tasks = ids.Select(async id =>
        {
            using var scope = _scopeFactory.CreateScope();
            var myService = scope.ServiceProvider.GetRequiredService<IMyBusinessService>();

            // 同一个 scope 内 db 上下文是同一个对象
            await myService.ProcessAsync1(id);
            await myService.ProcessAsync2(id);
        });

        await Task.WhenAll(tasks);
    }
}


热忱回答11

  • 正确用法

    //注册上下文:AOP里面可以获取IOC对象,如果有现成框架比如Furion可以不写这一行
    services.AddHttpContextAccessor();
    //注册SqlSugar用AddScoped
    services.AddScoped<ISqlSugarClient>(s =>
    {
        //Scoped用SqlSugarClient 
        SqlSugarClient sqlSugar = new SqlSugarClient (new ConnectionConfig()
        {
            DbType = SqlSugar.DbType.Sqlite,
            ConnectionString = "DataSource=sqlsugar-dev.db",
            IsAutoCloseConnection = true,
        },
       db =>
       {
          //每次上下文都会执行
                
          //获取IOC对象不要求在一个上下文
          //var log=s.GetService<Log>()
                    
          //获取IOC对象要求在一个上下文
          //var appServive = s.GetService<IHttpContextAccessor>();
          //var log= appServive?.HttpContext?.RequestServices.GetService<Log>();
                     
           db.Aop.OnLogExecuting = (sql, pars) =>
           {
            
           };
       });
        return sqlSugar;
    });

    注意点:

    services.AddScoped<ISqlSugarClient>(SqlSugarClient变量)//这种用法错误
    services.AddScoped<ISqlSugarClient>(s => SqlSugarClient变量)//这种用法错误
    services.AddScoped<ISqlSugarClient>(s => new  SqlSugarScope ..)//这种用法错误
    services.AddScoped<ISqlSugarClient>(s =>new SqlSugarClient.. )//正确

    建议直接复制我写的。这样100% OK

    0 回复
  • Leckun Leckun VIP0
    2025/6/24

    repository怎么弄?

    0 回复
  • fate sta fate sta VIP0
    2025/6/24

    @Leckun   

    using var scope = _serviceProvider.CreateScope();

    var myService = scope.ServiceProvider.GetRequiredService<仓储>();

    0 回复
  • 当定时任务里还有一层Task的时候,IServiceProvider经常会出现Cannot access a disposed object,后查资料发现IServiceProvider分父容器和子容器,注入创建的是子容器的IServiceProvider,当父容器的因异步调用立即返回后,父容器相关的会被释放,导致这个问题发生。

    后来改用IServiceScopeFactory问题解决。

    0 回复
  • fate sta fate sta VIP0
    2025/8/13

    @winnyrain:用例改成了IServiceScopeFactory

    0 回复
  • mousd mousd VIP0
    2025/9/3

    请问如果存在多个db连接,需要如何配置ioc注入呢

    0 回复
  • 请教一下,以下代码结构,支持多个不同数据库(oracle,postgre,sqlserver)连接方式是否正确?或者有什么建议,感谢!

    private static SqlSugarScope _dbs;

    /// <summary>

    /// SqlSugar 数据库实例

    /// </summary>

    public static SqlSugarScope Dbs

    {

        get {

            if (_dbs == null)

            {

                try

                {

                    // 读取 appsettings.json 中的 ConnectionConfigs 配置节点(多个数据库连接字符串)

                    _dbs = new SqlSugarScope(ConnectionConfigs,

                        db =>

                        {

                            //配置全局事件

                            ConfigureAopEvents(db);

                        });

                }

                catch (Exception ex)

                {

                    _logger.LogError(ex, "Failed to initialize SqlSugarScope.");

                    throw;

                }

            }

            return _dbs;

        }

    }


    private static ISqlSugarClient _dbERP;

    /// <summary>

    /// ERP系统数据库实例

    /// </summary>

    public static ISqlSugarClient DbERP

    {

        get

        {

            if (_dbERP == null)

            {

                try

                {

                    _dbERP = Dbs.GetConnection(ConfigId_ERP);

                    // 为该连接单独配置 AOP 事件

                    ConfigureAopEvents(_dbERP);

                }

                catch (Exception ex)

                {

                    _logger.LogError(ex, "Failed to get connection for ERP.");

                    throw;

                }

            }

            return _dbERP;

        }

    }



    private static ISqlSugarClient _dbOA;

    /// <summary>

    /// ERP系统数据库实例

    /// </summary>

    public static ISqlSugarClient DbOA

    {

        get

        {

            if (_dbOA == null)

            {

                try

                {

                    _dbOA = Dbs.GetConnection(ConfigId_OA);

                    // 为该连接单独配置 AOP 事件

                    ConfigureAopEvents(_dbOA);

                }

                catch (Exception ex)

                {

                    _logger.LogError(ex, "Failed to get connection for OA.");

                    throw;

                }

            }

            return _dbOA;

        }

    }


    //通用服务类注入SqlSugarClient

    public class GenericService<T> : IGenericService<T> where T : class, new()

    {

        private readonly ISqlSugarClient _db;

        private readonly IMemoryCache _cache;


        public GenericService(ISqlSugarClient db, IMemoryCache cache)

        {

            _db = db;

            _cache = cache;

        }


        /// <summary>

        /// 添加记录

        /// </summary>

        /// <param name="entity"></param>

        /// <returns></returns>

        public bool Insert(T entity)

        {

            return _db.Insertable<T>(entity).ExecuteCommand() > 0;

        }

    }


    /// <summary>

    /// SqlSugar数据库访问器

    /// </summary>

    public class DatabaseAccessor : IDatabaseAccessor

    {

        public ISqlSugarClient OA => DbContext.DbOA;

        public ISqlSugarClient ERP => DbContext.DbERP;

    }


    //具体对象服务类继承通用服务类,通过数据库访问器进行注入数据库SqlSugarClient

    public class UserService : GenericService<User>, IUserService, ITransient

    {

        private readonly IDatabaseAccessor _db;

        private readonly IMemoryCache _cache;


        public UserService(IDatabaseAccessor db, IMemoryCache cache):base(db.APS,cache)

        {

            _db = db;

            _cache = cache;

        }

    }


    0 回复
  • 我使用IOC注册,使用方法跟您一样:

    image.png

    但是还有错误,有2种错误(但猜测其实是同一种):

    1.     System.InvalidOperationException: 此连接不支持 MultipleActiveResultSets。

    2.     System.InvalidOperationException: 已有打开的与此 Connection 相关联的 DataReader,必须首先将它关闭。

    官网说这个方法偶发很低,但是我本地跑项目(前端vue+netcore webAPI),实测偶发很高,2-4次就发生一次。

    0 回复
  • @海绵宝宝:注册没有问题,关键是不是有用的地方有问题

    0 回复
  • 报错代码强制一下线程安全


        using var scope = _scopeFactory.CreateScope();
        var myService = scope.ServiceProvider.GetRequiredService<IMyBusinessService>();//也可以是ISqlSugarClient


    0 回复
  • @mousd:文档: new sqlsugraclient(configList) 多个传LSIT,文档:多租户有用法介绍

    0 回复