公司数据量已经达到亿级别,原有的单库主从方案不能满足使用了,所以我们进行了分库分表。分库造成原来项目直接注入DbContext的模式无法使用。现在数据连接字符串是根据请求的主体变动的,不能像以前那样直接构造函数注入。
工厂方法
所以,我们考虑使用工厂方法,根据请求主体生成不同的数据库连接。
这里我们使用了IHttpContextAccessor来获取请求上下文,然后根据请求上下文生成数据库连接,ConnectionFactory工厂代码如下
//构造函数 public ConnectionFactory(IHttpContextAccessor accessor) { string conStr; #if DEBUG conStr = ConfigurationManager.GetValue("ConnectionString"); #else conStr = accessor.GetConnectionString(); #endif Connection = string.IsNullOrEmpty(conStr) ? new MySqlConnection(ConfigurationManager.GetValue("ConnectionString")) : new MySqlConnection(conStr); } /// <summary> /// 根据传入字符串更改连接 /// </summary> /// <param name="connectionStr"></param> /// <returns></returns> public MySqlConnection ExchangeConnection(string connectionStr) { Connection=new MySqlConnection(connectionStr); return Connection; } //对外公开的连接 public MySqlConnection Connection { get; set; }
使用方法
直接注入工厂,然后获取Connection属性
private readonly IDbConnection _connection; public CallHistoryRepository(ConnectionFactory connectionFactory) { _connection = connectionFactory.Connection; }
在startup中注册Scoped类型的注入
services.AddScoped<ConnectionFactory>();
遇到的问题
我们有些场景需要更换使用的数据库连接,但是如果我们使用ExchangeConnection方法,那么工厂方法里面的连接是改变成最新的了,但是类中的私有变量IDbConnection _connection引用的还是构造函数注入的老的数据库连接,这时候可以考虑使用懒加载,如下
private readonly Lazy<IDbConnection> _connectionLazy; public CallHistoryRepository(ConnectionFactory connectionFactory) { _connectionLazy = new Lazy<IDbConnection>(()=>connectionFactory.Connection); }
这样,无论你在service层更改几次对应的数据库连接,仓储层都会使用最新的连接,完成特定操作。