22组地域Oracle+SQL数据库动态连接的DI最佳实践咨询
多地域动态数据库场景下的DI最佳实践
你的当前实现思路是可行的,针对22个地域对应独立数据库的场景,结合依赖注入可以从以下几个方向优化,让架构更清晰、可维护:
1. 保持Scoped生命周期的合理性
你用AddScoped注册IOracleDataAccess和ISQLDataAccess是完全正确的选择:
- Scoped服务会为每个用户请求创建独立实例,刚好匹配"每个请求对应一个地域数据库"的需求,避免了Singleton全局实例带来的线程安全问题(比如不同用户的连接字符串互相覆盖)。
- 绝对不要改成Singleton模式,Singleton是全局唯一的,无法适配多地域动态切换的场景。
2. 抽象连接字符串解析逻辑
当前直接在LoadData里通过配置键拿连接字符串的方式可以进一步内聚,建议抽象出专门的解析器:
public interface ILocationConnectionResolver { string GetOracleConnString(string locationId); string GetSqlConnString(string locationId); } public class LocationConnectionResolver : ILocationConnectionResolver { private readonly IConfiguration _config; public LocationConnectionResolver(IConfiguration config) { _config = config; } public string GetOracleConnString(string locationId) { // 对应配置文件里的键格式:Oracle-Location01、Oracle-Location02... return _config.GetConnectionString($"Oracle-{locationId}"); } public string GetSqlConnString(string locationId) { return _config.GetConnectionString($"SQL-{locationId}"); } }
然后把这个解析器注册为Singleton(无状态,全局复用即可):
builder.Services.AddSingleton<ILocationConnectionResolver, LocationConnectionResolver>();
之后在OracleDataAccess或业务服务中注入这个解析器,代替直接传递连接字符串名称,逻辑更清晰。
3. 把地域信息注入请求上下文
现在业务方法里需要传递userLocationId,可以改为在请求管道早期把地域信息存入上下文,避免重复传递:
// 自定义用户上下文类 public class UserContext { public string LocationId { get; set; } } // 注册为Scoped,每个请求一个实例 builder.Services.AddScoped<UserContext>(); // 中间件中从AD获取地域并设置 app.Use(async (context, next) => { var userContext = context.RequestServices.GetRequiredService<UserContext>(); // 从当前登录用户的AD信息中提取地域Id userContext.LocationId = ExtractLocationFromAd(context.User); await next(); });
之后在ProductDataService中直接注入UserContext,不用再把userLocationId作为方法参数:
public async Task<List<Product>> GetProducts() { var productQuery = QueryReader.ReadQueryFile(QuerySubFolderName, "products.sql"); var locationData = await _locationService.GetLocationById(_userContext.LocationId); var data = await _oracleDb.LoadData<Product, dynamic>(productQuery, new { }, locationData.WMSDB); return data; }
4. 数据库连接的优化管理
你当前用using块创建数据库连接的方式是正确的:
- Oracle和SQL Server默认启用连接池,
using块会自动将连接释放回池,不需要手动管理连接复用。 - 不要长期持有连接实例,
using的方式能确保连接及时回收,避免资源泄漏。
5. 避免过度抽象
如果不同地域的业务逻辑完全一致,不需要为每个地域单独创建仓库或服务类,当前的通用数据访问层设计足够满足需求,过度抽象反而会增加维护成本。
内容的提问来源于stack exchange,提问作者causita
相关产品推荐
相关产品推荐

