基於 EntityFramework 的數據庫主從讀寫分離架構(1) - 原理概述和基本功能實現

     回到目錄,完整代碼請查看https://github.com/cjw0511/NDF.Infrastructure)中的目錄:
     src\ NDF.Data.EntityFramework\MasterSlaves
 
    在本上的上一篇博文中(基於 EntityFramework 的數據庫主從讀寫分離服務插
件, http://www.cnblogs.com/cjw0511/p/4391092.html),概述性的介紹了本身基於 EF6 寫的一個用於數據庫主從讀寫分離服務的一個插件。由於時間關係,上一篇博文只講到了該插件的功能概述和基本用法。今天正好有空,就花點時間構思了這篇博文,和你們一塊兒來交流一下,本人基於 EF6 的數據庫主從讀寫分離服務插件是如何構思、設計以及編碼實現的。
 
    首先,在繼續進行本文的後續內容閱讀以前,應該先對一些相關知識點有所瞭解,包括但不限於以下幾個方面:
    一、ADO.NET 基礎知識;
    二、EntityFramework 的功能和基本用法;
    三、數據庫讀寫分離的概念( http://baike.baidu.com/view/3372624.htm);
    四、數據庫主從複製功能的基本配置(不一樣數據庫系統配置方式不一樣);
    以上幾點是閱讀和實現本文所述的數據庫主從讀寫分離的基礎知識,本文就不作詳細贅述了,若有想在這些方面另需瞭解的同窗,請自行補課。
 
    好了,接下來進入正題吧。
    咱們都知道,在應用程序開發中,要實現數據庫的主從讀寫分離操做,也就是讓全部的數據變動操做請求都指向 Master(主) 服務器,而全部的數據查詢請求都指向 Slave(從)服務器,其根本就在於構建 ADO.NET 的 DbConnection 鏈接時,ConnectionString 的指向不一樣。在之前,沒有用 ORM 框架時,咱們可能經過自定義一些諸如 DataAccessHelper 的工具類,在工具類型定義兩大類型的 API,其一爲數據庫變動操做,其二爲數據查詢操做。在數據庫變動操做中,生成的 DbConnection 的鏈接地址指向 Master 服務器;在數據查詢操做時,生成的 DbConnection 指向另外一臺 Slave 服務器。
 
    而現在,因爲須要分離關注點、提升代碼複用性和編碼工做效率、下降程序員對 sql 的知識依賴等諸多緣由,咱們用上了 EntityFramework、NHibernate 等相似的 ORM 框架。實際上,在 ORM 框架中,要實現數據庫讀寫分離,和咱們早期直接用 ADO.NET 來實現該功能的原理是同樣的。而不一樣之處,主要就在於,ORM 框架通常提供了AOP 架構的切面注入方式,讓咱們能夠在某個關注點上添加咱們自定義的操做。
 
    在 EntityFramework 的 6.1 版本中,新增了一個命名空間 System.Data.Entity.Infrastructure.Interception,該命名空間主要就是提供了一個面向切面的程序注入功能,讓咱們能夠在 EF 最終向數據庫提交 DbCommand 執行請求先後,攔截到該動做並執行咱們自定義的其餘附加動做。基本的作法爲:
    一、自定義一個 System.Data.Entity.Infrastructure.Interception.DbCommandInterceptor 類型的子類;
    二、在該自定義類型中重寫方法 ReaderExecuting、ReaderExecuted、ScalarExecuting、ScalarExecuted、NonQueryExecuting、NonQueryExecuted,方法體內便可實現本身對查詢命令、更改命令的執行先後附加動做;
    三、經過 System.Data.Entity.Infrastructure.Interception.DbInterception.Add 方法,將該自定義的類型實例添加至 EF 執行上下文中;
    完成以上幾個步驟後,EF 便可在每次執行增刪改或查詢命令先後,額外咱們咱們定義的其餘動做。
 
    廢話很少說,下面貼上一段代碼,用於表示實現 EF 讀寫分離效果的 DbCommandInterceptor 基本實現:
 1 public class DbMasterSlaveCommandInterceptor : DbCommandInterceptor
 2     {
 3         private string masterConnectionString = "server=192.168.0.99;port=3306;user id=root;password=123456;persistsecurityinfo=True;database=testdb";
 4         private string slaveConnectionString = "server=192.168.0.101;port=3306;user id=root;password=123456;persistsecurityinfo=True;database=testdb";
 5         public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
 6         {
 7             this.UpdateConnectionString(interceptionContext, this.slaveConnectionString);
 8         }
 9         public override void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
10         {
11             this.UpdateConnectionString(interceptionContext, this.slaveConnectionString);
12         }
13         public override void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
14         {
15             this.UpdateConnectionString(interceptionContext, this.masterConnectionString);
16         }
17         private void UpdateConnectionString(DbInterceptionContext interceptionContext, string connectionString)
18         {
19             foreach (var context in interceptionContext.DbContexts)
20             {
21                 this.UpdateConnectionString(context.Database.Connection, connectionString);
22             }
23         }
24         private void UpdateConnectionString(DbConnection conn, string connectionString)
25         {
26             ConnectionState state = conn.State;
27             if (state == ConnectionState.Open)
28                 conn.Close();
29             conn.ConnectionString = connectionString;
30             if (state == ConnectionState.Open)
31                 conn.Open();
32         }
33     }

 

    接着,在 Global.asax 的啓動代碼中將該 類型的實體注入 EF 全局執行上下文中。html

 

1 public class MyHttpApplication : HttpApplication
2     {
3         protected void Application_Start()
4         {
5             DbInterception.Add(new DbMasterSlaveCommandInterceptor());
6         }
7     }

 

    怎麼樣,原理是否是很簡單?固然,若是想要實現一些豐富的配置和擴展功能,就還須要不少其餘的代碼了,關於這些本人將會在後續文章中逐步介紹!git

相關文章
相關標籤/搜索