回到目录,完整代码请查看https://github.com/cjw0511/NDF.Infrastructure)中的目录:
     src\ NDF.Data.EntityFramework\MasterSlaves
 
    在本上的上一篇博文中(基于 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 基本实现:
 public class DbMasterSlaveCommandInterceptor : DbCommandInterceptor
{
private string masterConnectionString = "server=192.168.0.99;port=3306;user id=root;password=123456;persistsecurityinfo=True;database=testdb";
private string slaveConnectionString = "server=192.168.0.101;port=3306;user id=root;password=123456;persistsecurityinfo=True;database=testdb";
public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
{
this.UpdateConnectionString(interceptionContext, this.slaveConnectionString);
}
public override void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
{
this.UpdateConnectionString(interceptionContext, this.slaveConnectionString);
}
public override void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
{
this.UpdateConnectionString(interceptionContext, this.masterConnectionString);
}
private void UpdateConnectionString(DbInterceptionContext interceptionContext, string connectionString)
{
foreach (var context in interceptionContext.DbContexts)
{
this.UpdateConnectionString(context.Database.Connection, connectionString);
}
}
private void UpdateConnectionString(DbConnection conn, string connectionString)
{
ConnectionState state = conn.State;
if (state == ConnectionState.Open)
conn.Close();
conn.ConnectionString = connectionString;
if (state == ConnectionState.Open)
conn.Open();
}
}

接着,在 Global.asax 的启动代码中将该 类型的实体注入 EF 全局执行上下文中。

 public class MyHttpApplication : HttpApplication
{
protected void Application_Start()
{
DbInterception.Add(new DbMasterSlaveCommandInterceptor());
}
}

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

基于 EntityFramework 的数据库主从读写分离架构(1) - 原理概述和基本功能实现的更多相关文章

  1. 基于 EntityFramework 的数据库主从读写分离架构 - 目录

    基于 EntityFramework 的数据库主从读写分离架构       回到目录,完整代码请查看(https://github.com/cjw0511/NDF.Infrastructure)中的目 ...

  2. 基于 EntityFramework 的数据库主从读写分离架构(2)- 改进配置和添加事务支持

        回到目录,完整代码请查看(https://github.com/cjw0511/NDF.Infrastructure)中的目录:      src\ NDF.Data.EntityFramew ...

  3. 基于 EntityFramework 的数据库主从读写分离服务插件

    基于 EntityFramework 的数据库主从读写分离服务插件 1. 版本信息和源码 1.1 版本信息 v1.01 beta(2015-04-07),基于 EF 6.1 开发,支持 EF 6.1 ...

  4. 基于 EntityFramework 的数据库主从读写分离

    现在刚开始来研究EntityFramwork,起初是在vs2012中通过工具来创建EF ,但是对我这种不熟悉菜鸟来说 有很多业务用EF做出来还是有点难度的,今天来手动搭建一个EF框架,大神勿喷

  5. 基于Amoba实现mysql主从读写分离

    一.Amoeba简介           Amoeba是一个以MySQL为底层数据存储,并对应用提供MySQL协议接口的proxy.它集中地响应应用的请求,依据用户事先设置的规则,将SQL请求发送到特 ...

  6. MySQL搭建主从数据库 实现读写分离

    首先声明,实际生产中,网站为了提高用户体验,性能等,将数据库实现读写分离是有必要的,我们让主数据库去写入数据,然后当用户查询的时候,然后在从数据库读取数据,故能减轻数据库的压力,实现良好的用户体验! ...

  7. Amoeba搞定mysql主从读写分离

    前言:一直想找一个工具,能很好的实现mysql主从的读写分离架构,曾经试用过mysql-proxy发现lua用起来很不爽,尤其是不懂lua脚本,突然发现了Amoeba这个项目,试用了下,感觉还不错,写 ...

  8. Amoeba实现mysql主从读写分离

    Amoeba实现mysql主从读写分离 这段在网上看了下关于amoeba的文章,总体感觉好像要比mysql-proxy好的多,也参考了不少的资料,此文章可能与其他文章作者会有雷同的地方,请谅解,但是此 ...

  9. Mycat - 实现数据库的读写分离与高可用

    前言 开心一刻 上语文课,不小心睡着了,坐在边上的同桌突然叫醒了我,并小声说道:“读课文第三段”.我立马起身大声读了起来.正在黑板写字的老师吓了一跳,老师郁闷的看着我,问道:“同学有什么问题吗?”,我 ...

随机推荐

  1. SqlServer 数据库负载均衡【转】

    负载均衡集群是由一组相互独立的计算机系统构成,通过常规网络或专用网络进行连接,由路由器衔接在一起,各节点相互协作.共同负载.均衡压力,对客户端来说,整个群集可以视为一台具有超高性能的独立服务器. 1. ...

  2. BZOJ3632: 外太空旅行

    BZOJ1547: 周末晚会 https://lydsy.com/JudgeOnline/problem.php?id=1547 分析: 对于一个串旋转若干次会回到本身,旋转次数即是同构个数,这个东西 ...

  3. jQuery的ajax跨域实现

    今天有人问我跨域ajax请求是否可以发送,之前没接触过此类问题,没答上,后来查了下,以下备忘. 我在本地建了三个站点,并设置了host文件模拟跨子域和跨全域 coolkissbh.com blog.c ...

  4. Aes加密算法加密模式介绍

    本文转自:https://www.jianshu.com/p/582d3a47729a AES,高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中 ...

  5. PMODB GT202 WIFI的使用

    pHTTPSession = (P_HTTP_SESSION)malloc(ALIGN(sizeof(HTTP_SESSION))) PMODA/PMODB都可做WIFI使用,现介绍PMODB WIF ...

  6. php单链表实现

    php单链表实现 <?php //单链表 class Hero{ public $no; public $name; public $nickname; public $next=null; f ...

  7. codeforce 980B - Marlin(构造)

    Marlin time limit per test 1 second memory limit per test 256 megabytes input standard input output ...

  8. Perl参考函数/教程

    这是标准的Perl解释器所支持的所有重要函数/功能的列表.在一个函数中找到它的详细信息. 功能丰富的 Perl:轻松调试 Perl Perl脚本的调试方法 perl 入门教程 abs - 绝对值函数 ...

  9. tp5操作mongo

    1.通过composer安装 composer require mongodb/mongodb 2.使用 <?php /** * @author: jim * @date: 2017/11/17 ...

  10. PHP手机号中间四位用星号*代替显示

    三种实现方式 <?php $tel = '12345678910'; //1.字符串截取法 $new_tel1 = substr($tel, 0, 3).'****'.substr($tel, ...