多库操作:多个数据库的动态切换(一)
▼
更多精彩推薦,上午11點到達
▼
在平時的開發中,受到傳統模式的影響,我們都是習慣了單一的數據庫表操作,把數據都建到一個庫里邊,然后進行增刪改查,這個是很經典的開發模式。
但是隨著項目開發,總會出現這樣的應用場景:
1、我們新的系統建立了新庫,但是老板讓我們把具有相同結構的老數據庫也帶上(導入到一起或者定時同步,這里不討論)
2、項目慢慢變大,我們要分庫分表了,可能訂單數據和用戶數據被分開了,但是同一個api業務邏輯里,可能我們需要操作多個DB,比如我正在走的是主庫,然后有一個操作,需要把數據從另一個DB里區保存或者查詢。
3、想在測試的時候,同時無縫測試多個庫連接,比如我的Blog.Core,每次我提交一個版本,都需要對Sqlite、MySql、MSSql(LocalDB)等同時做測試,那我就想在不停掉項目的前提下,做多庫測試。
其實說了那么多,就是想實現一個工作,就是多庫操作,畢竟這是一個趨勢,今天我們就簡單說一下多庫操作的第一彈 —— 動態切換數據庫。過程很簡單,這里就先說一下吧。
鳴謝:@Game結束 小伙伴提供思路和代碼。
1、修改配置DB連接字符串集合
目前我的Blog.Core項目中,使用的是SqlSugar的ORM,如果你用其他的,也是可以的,思路都是一樣的,可能具體操作細節和寫法上不太一樣。
修改我們的appsettings.json,配置連接字符串
這個設計很簡單,我們可以配置到appsettings.json里,同時也可以配置到內存里,至于能不能放到數據庫里,我還沒有操作過,不過放到配置文件里已經基本可以了。
2、配置連接數據對象
我們這里使用的既然是Sqlsugar,那就把相應的連接配置對象注入到服務里,本來使用的是上下文,但是后來為了事務,也發現上下文有點兒多余,因為sqlsugar自帶了部分上下文的功能,所以就直接使用的ISqlSugarClient。
那首先我們就需要把剛剛json配置文件的連接字符串,封裝一下:
在 Common 層的 BaseDBConfig 中,創建操作類:
public class MutiDBOperate{public string ConnId { get; set; }public string Conn { get; set; }public DataBaseType DbType { get; set; }}然后把json數據封裝一下:
public static List<MutiDBOperate> MutiConnectionString => MutiInitConn();public static List<MutiDBOperate> MutiInitConn(){List<MutiDBOperate> listdatabase = new List<MutiDBOperate>();string Path = "appsettings.json";using (var file = new StreamReader(Path))using (var reader = new JsonTextReader(file)){var jObj = (JObject)JToken.ReadFrom(reader);if (!string.IsNullOrWhiteSpace("DBS")){var secJt = jObj["DBS"];if (secJt != null){for (int i = 0; i < secJt.Count(); i++){if (secJt[i]["Enabled"].ObjToBool()){listdatabase.Add(SpecialDbString(new MutiDBOperate(){ConnId = secJt[i]["ConnId"].ObjToString(),Conn = secJt[i]["Connection"].ObjToString(),DbType = (DataBaseType)(secJt[i]["DBType"].ObjToInt()),}));}}}}return listdatabase;}}3、注入服務
這里要說一下,既然是多個庫連接,我就需要一個主庫,就是當前的DB,為了達到切換的目的,我也在配置文件里做了相應的配置:
這個值,就是當前某一個連接對象的ConnId。同時也為了在代碼里能控制這個值,我采用對象靜態類的方式:
namespace Blog.Core.Common.DB {public static class MainDb{//?這個id,就是我們配置文件的idpublic static string CurrentDbConnId = "1";} }現在我們把剛剛的配置數據對象一起注入到服務里:
/// <summary>/// SqlSugar 啟動服務/// </summary>public static class SqlsugarSetup{public static void AddSqlsugarSetup(this IServiceCollection services){if (services == null) throw new ArgumentNullException(nameof(services));// 把多個連接對象注入服務,這里可以采用Transient瞬態,也可以Scopeservices.AddTransient(o =>{List<ISqlSugarClient> sqlSugarClients = new List<ISqlSugarClient>();var beforeDbConnect = BaseDBConfig.MutiConnectionString;var index = beforeDbConnect.FindIndex(x => x.ConnId == MainDb.CurrentDbConnId);if (index > 0){// 做一個交換,切換主db連接放到第一位var firstDb = beforeDbConnect[0];var changeDb = beforeDbConnect[index];beforeDbConnect[index] = firstDb;beforeDbConnect[0] = changeDb;}beforeDbConnect.ForEach(m =>{sqlSugarClients.Add(new SqlSugarClient(new ConnectionConfig(){ConfigId = m.ConnId,ConnectionString = m.Conn,DbType = (DbType)m.DbType,IsAutoCloseConnection = true,//InitKeyType = InitKeyType.SystemTable}));});return sqlSugarClients;});}}4、倉儲構造函數注入DB
目前我采用的架構是【service+repository+unitofwork】的模式,所以我們獲取的Db就是ISqlSugarClient實例,那我們就把它注入進去。
在 UnitOfWork 的構造函數中,注入:
private readonly List<ISqlSugarClient> _sqlSugarClients;public UnitOfWork(List<ISqlSugarClient> sqlSugarClients){// 每次取最上邊的db,這個順序已經在注冊服務的時候,切換好了_sqlSugarClient?=?sqlSugarClients[0];??}5、其他修改
我們修改了db連接方式,那項目啟動時候Seed種子數據的上下文也需要更改一下:
6、做下測試,動態切換
那到底能不能使用呢,這里我們測試一下:
首先我們打開兩個數據庫連接,一個是Sqlite,一個是MSSql,同時我們在兩個各自的博客表中,數據做區分。
我們先執行一下blog查詢,然后把maindb切換成"2"頻道,也就是mssql的:
并不完美,遺留問題
這樣我們每次訪問api,是可以單獨的做控制,但是這里有一個問題,就是我們同一個api內,是無法實現動態切換的目的的,我也在研究,在下篇文章中,我會想辦法解決這個問題。
總結
以上是生活随笔為你收集整理的多库操作:多个数据库的动态切换(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Amazon、Linux基金会开发边缘网
- 下一篇: 为什么需要动态SQL