最近做個分庫分表專案,用到schema的切換感覺還是有些坑的,在此分享下。
先簡要說下我們的分庫分表
分庫分表規則
我定的規則是,訂單號(數字)除以16,得出的結果為這個訂單所在的資料庫,然後他的餘數代表他所在這個庫裡面的哪個表。
然後在一個庫裡面有16個表,這個怎麼實現呢?比較齪的辦法是 Order1/Order2這樣,不過後來我想了下,資料庫預設(我們是Sql Server)是有schema的(預設是dbo的那個東西),
然後我就打起這個東西的主意,後續跟dba確認方案可行後,就決定比如在同一個庫裡,第一套訂單表是 p0.Order,第二套訂單表就是p1.Order(有效取值 p0~p15)。
程式碼設計
如果說每次操作訂單,你都要記得要先根據訂單號拆分規則,找到這是哪個資料庫,再去找這是哪個schema,我覺得這程式碼也別寫了,放棄把,這是不可維護的程式碼,不具備可持續發展性。
我們必須要將一個分庫分表這麼一件事,抽象為某個單一的邏輯。
於是乎,DbContext是個好東西!
當我們在說Ef的時候,實際上我們在討論的主要就是他裡面的DbContext。而一個DbContext,則邏輯上代表了一個資料庫對映(包含資料庫連線/表等和資料庫相關的所有配置的集合)。
只要我們將分庫分表這件事,抽象為如何獲取一個DbContext,之後在對這個DbContext做你想做的操作,那麼一切事情就簡單多了!
於是乎我設計了這麼一個介面:
你給我一個訂單號,我還你一個DbContext~
正題
如何讓DbContext支援分庫分表
這裡主要有2個問題,一個是如何改連線字串,另一個如何改schema。
問題1簡單,建立DbContext的時候本來就是要串連線字串進去的,直接這裡構造好連線字串即可。
問題2比較複雜,也是這篇文章主要內容,首先我的設計是在建立DbContext,傳入schema,在OnModelCreating裡用這個schema初始化。
程式碼是這樣子的:
於是乎你第一次建立DbContext的時候,schema是什麼(別在意我程式碼變數名當時寫錯了這麼個細節),就永遠是什麼,後續你重覆建立其他DbContext的時候其實這句話並不能讓你修改schema。
後面我發覺,EfCore在指定表名的時候,是可以順帶指定schema的,於是乎在改下,改成了類似這樣:
然而實踐證明依然並沒有什麼卵用。
坑了2次後我嚴重懷疑efcore裡一定有某種級別的快取機制,使得初次賦值之後某些資訊不會再被更新(甚至於懷疑到efcore2.x引入的DbContextPool,然而我都是new出來的我沒pool啊)。
後面一通亂找後不記得再哪個網址(但是記得一定是stackoverflow裡)找到了對這個類 IModelCacheKeyFactory的一些描述。
好像是efcore會對Model(你的物體)和DbContext之間產生一個快取,而我的分庫分表用的DbContext只有一個(只是動態修改了某些引數配置),於是乎覺得應該就是這個東西快取了的關係導致,然後我重寫了這貨的實現:
本質就是將DbContext裡的當前的Schema暴露出給ModelCacheKey讀取,然後進行Equal比較的時候Schema也作為一個Equal的因素,當兩者比較不等的時候,就不會再採用之前錯誤Schema的快取了
最後在建立DbContextOptionBuilder的時候Replace一下
builder.ReplaceService
即可完成
後續親測都能動態切換schema,圓滿完成。
原文地址:https://www.cnblogs.com/leolaw/p/10461156.html
.NET社群新聞,深度好文,歡迎訪問公眾號文章彙總 http://www.csharpkit.com