fix: 区分 SqlSugarScope 和 SqlSugarClient 使用场景

区分:
- GetSqlSugarScope(): 返回 SqlSugarScope,用于 DI 注入(Singleton)
- GetSqlSugarClient(): 返回 SqlSugarClient,用于后台任务(每次创建新实例)

原因:
- SqlSugarScope 使用 AsyncLocal 隔离上下文
- Task.Run 后台线程中 AsyncLocal 可能无法正确传递
- 后台任务使用 SqlSugarClient 更安全,每个实例独立连接

使用:
- DI 注入:GetSqlSugarScope()
- Repository 后台写入:GetSqlSugarClient()
- MySQL 连接池复用底层 TCP 连接,性能开销小
This commit is contained in:
OpenClaw Agent 2026-03-25 02:42:26 +00:00
parent cbe0ac9f4a
commit dc50dfc917
2 changed files with 65 additions and 26 deletions

View File

@ -12,7 +12,7 @@ public static class DatabaseExtensions
// 使用 Singleton 注册,整个应用共享一个实例 // 使用 Singleton 注册,整个应用共享一个实例
services.AddSingleton<ISqlSugarClient>(s => services.AddSingleton<ISqlSugarClient>(s =>
{ {
return SqlSugarConfig.GetSqlSugarClient(); return SqlSugarConfig.GetSqlSugarScope();
}); });
services.AddScoped<DatabaseService>(); services.AddScoped<DatabaseService>();

View File

@ -15,6 +15,9 @@ public static class SqlSugarConfig
_configuration = configuration; _configuration = configuration;
} }
/// <summary>
/// 获取 SqlSugarClient 实例(用于后台任务,每次创建新实例)
/// </summary>
public static ISqlSugarClient GetSqlSugarClient() public static ISqlSugarClient GetSqlSugarClient()
{ {
if (_configuration == null) if (_configuration == null)
@ -22,36 +25,41 @@ public static class SqlSugarConfig
throw new InvalidOperationException("SqlSugarConfig has not been initialized. Call Initialize() first."); throw new InvalidOperationException("SqlSugarConfig has not been initialized. Call Initialize() first.");
} }
// 优先从环境变量读取连接字符串 var connectionString = GetConnectionString();
var connectionString = Environment.GetEnvironmentVariable("ConnectionStrings__Default")
?? _configuration.GetConnectionString("Default")
?? throw new InvalidOperationException("Connection string 'Default' not found in environment variables or configuration.");
// MySQL 连接池优化配置 // 使用 SqlSugarClient非 Scope每次创建独立实例
// 添加连接池参数提高稳定性 // 适合后台任务、Task.Run 场景
if (!connectionString.Contains("Pooling=", StringComparison.OrdinalIgnoreCase)) return new SqlSugarClient(new ConnectionConfig()
{ {
connectionString += ";Pooling=true"; ConnectionString = connectionString,
} DbType = DbType.MySql,
if (!connectionString.Contains("MaximumPoolSize=", StringComparison.OrdinalIgnoreCase)) IsAutoCloseConnection = true,
InitKeyType = InitKeyType.Attribute,
ConfigureExternalServices = new ConfigureExternalServices
{
EntityService = (property, column) =>
{
if (property.PropertyType == typeof(DateTime))
{
column.DataType = "datetime(3)";
}
}
}
});
}
/// <summary>
/// 获取 SqlSugarScope 实例(用于 DI 注入Singleton/Scoped
/// </summary>
public static ISqlSugarClient GetSqlSugarScope()
{
if (_configuration == null)
{ {
connectionString += ";MaximumPoolSize=100"; throw new InvalidOperationException("SqlSugarConfig has not been initialized. Call Initialize() first.");
}
if (!connectionString.Contains("MinimumPoolSize=", StringComparison.OrdinalIgnoreCase))
{
connectionString += ";MinimumPoolSize=5";
}
// 连接超时和生命周期
if (!connectionString.Contains("ConnectionTimeout=", StringComparison.OrdinalIgnoreCase))
{
connectionString += ";ConnectionTimeout=30";
}
// 连接空闲超时,避免使用长时间空闲的连接
if (!connectionString.Contains("ConnectionIdleTimeout=", StringComparison.OrdinalIgnoreCase))
{
connectionString += ";ConnectionIdleTimeout=180";
} }
var connectionString = GetConnectionString();
return new SqlSugarScope(new ConnectionConfig() return new SqlSugarScope(new ConnectionConfig()
{ {
ConnectionString = connectionString, ConnectionString = connectionString,
@ -70,4 +78,35 @@ public static class SqlSugarConfig
} }
}); });
} }
private static string GetConnectionString()
{
var connectionString = Environment.GetEnvironmentVariable("ConnectionStrings__Default")
?? _configuration!.GetConnectionString("Default")
?? throw new InvalidOperationException("Connection string 'Default' not found in environment variables or configuration.");
// MySQL 连接池优化配置
if (!connectionString.Contains("Pooling=", StringComparison.OrdinalIgnoreCase))
{
connectionString += ";Pooling=true";
}
if (!connectionString.Contains("MaximumPoolSize=", StringComparison.OrdinalIgnoreCase))
{
connectionString += ";MaximumPoolSize=100";
}
if (!connectionString.Contains("MinimumPoolSize=", StringComparison.OrdinalIgnoreCase))
{
connectionString += ";MinimumPoolSize=5";
}
if (!connectionString.Contains("ConnectionTimeout=", StringComparison.OrdinalIgnoreCase))
{
connectionString += ";ConnectionTimeout=30";
}
if (!connectionString.Contains("ConnectionIdleTimeout=", StringComparison.OrdinalIgnoreCase))
{
connectionString += ";ConnectionIdleTimeout=180";
}
return connectionString;
}
} }