zoukankan      html  css  js  c++  java
  • 基于 EntityFramework 的数据库主从读写分离架构(1)

        回到目录,完整代码请查看https://github.com/cjw0511/NDF.Infrastructure)中的目录:
         src NDF.Data.EntityFrameworkMasterSlaves
     
        在本上的上一篇博文中(基于 EntityFramework 的数据库主从读写分离服务插
    件,http://www.cnblogs.com/cjw0511/p/4391092.html),概述性的介绍了自己基于 EF6 写的一个用于数据库主从读写分离服务的一个插件。因为时间关系,上一篇博文只讲到了该插件的功能概述和基本用法。今天正好有空,就花点时间构思了这篇博文,和大家一起来交流一下,本人基于 EF6 的数据库主从读写分离服务插件是如何构思、设计以及编码实现的。
     
        首先,在继续进行本文的后续内容阅读之前,应该先对一些相关知识点有所了解,包括但不限于如下几个方面:
        1、ADO.NET 基础知识;
        2、EntityFramework 的功能和基本用法;
        3、数据库读写分离的概念(http://baike.baidu.com/view/3372624.htm);
        4、数据库主从复制功能的基本配置(不同数据库系统配置方式不同);
        以上几点是阅读和实现本文所述的数据库主从读写分离的基础知识,本文就不做详细赘述了,如有想在这些方面另需了解的同学,请自行补课。
     
        好了,接下来进入正题吧。
        我们都知道,在应用程序开发中,要实现数据库的主从读写分离操作,也就是让所有的数据变更操作请求都指向 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 执行请求前后,拦截到该动作并执行我们自定义的其他附加动作。基本的做法为:
        1、自定义一个 System.Data.Entity.Infrastructure.Interception.DbCommandInterceptor 类型的子类;
        2、在该自定义类型中重写方法 ReaderExecuting、ReaderExecuted、ScalarExecuting、ScalarExecuted、NonQueryExecuting、NonQueryExecuted,方法体内即可实现自己对查询命令、更改命令的执行前后附加动作;
        3、通过 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 全局执行上下文中。

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

        怎么样,原理是不是很简单?当然,如果想要实现一些丰富的配置和扩展功能,就还需要很多其他的代码了,关于这些本人将会在后续文章中逐步介绍!

  • 相关阅读:
    第04组(64) 需求分析报告
    第04组(64) 团队展示
    结对编程作业
    Python单元测试框架 Unittest 的简单使用方法
    第一次个人编程作业
    第09组 Alpha冲刺 总结
    Swagger 工具集
    第09组 Alpha冲刺(6/6)
    第09组 Alpha冲刺(5/6)
    第09组 Alpha冲刺(4/6)
  • 原文地址:https://www.cnblogs.com/cjw0511/p/4398267.html
Copyright © 2011-2022 走看看