读写分离子系统 - C# SQL分发子系统(ADO.NET,不支持EF)

这次介绍的这个框架只适用于中小项目,并且各个读写数据库结构是一致的情况,还要并且是写入数据库只有1台情况。

我们来看看这个子系统适用的场景:

我们来看这个子系统的配置文件:

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <SQLDispatcher>
  3. <WritableDB>Server=.;Database=d1;User Id=sa;Password=111111;</WritableDB> //唯一的主数据库(写入DB)
  4. <ReadDBs>
  5. <DB>Server=.;Database=d2;User Id=sa;Password=111111;</DB> //这些是普通的对等的读数据库,只是做了些普通索引优化
  6. <DB>Server=.;Database=d3;User Id=sa;Password=111111;</DB> //同上
  7. <DB>Server=.;Database=d4;User Id=sa;Password=111111;</DB> //同上
  8. </ReadDBs>
  9. <DedicatedReadDBs>
  10. <DedicatedRegion>
  11. <Region>Optimization_Sales</Region>                //这个区域代表所列出来的DB是专门针对销售报表优化索引的数据库
  12. <DB>Server=.;Database=d5;User Id=sa;Password=111111;</DB>
  13. <DB>Server=.;Database=d6;User Id=sa;Password=111111;</DB>
  14. </DedicatedRegion>
  15. <DedicatedRegion>
  16. <Region>Optimization_HR</Region>                  //这样的专门Region可以有多个区域
  17. <DB>Server=.;Database=d7;User Id=sa;Password=111111;</DB>
  18. </DedicatedRegion>
  19. </DedicatedReadDBs>
  20. </SQLDispatcher>

上述配置文件的读取,略。

业务层中,可以做到这样的写法:

  1. [AOPServiceEnabled()] //这句是为了和AOP代理挂钩
  2. public class OrderQueryService : OrderQueryServiceInterface
  3. {
  4. IOrderQueryServiceDataProvider dp = new OrderQueryServiceSqlDataProvider();
  5.  
  6. public override QueryResult<QueryDto.OrderDto> QueryByFirstName(string firstName, PagingInfo pgInfo)
  7. { //这个函数没有加SQLDispatcher标记,系统会自己选择sql连接(写入sql:就那1个;读取sql:从ReadDBs中取模选中1个)
  8. QueryResult<QueryDto.OrderDto> lst=dp.QueryByFirstName(firstName, pgInfo);
  9. foreach (OrderDto o in lst.List)
  10. o.FirstName += DateTime.Now.ToString();
  11. return lst;
  12. }
  13.  
  14. [SQLDispatcher("Optimization_Sales")] //显式指定sql语句走 Optimization_Sales区域
  15. public override QueryResult<QueryDto.OrderDto> QueryByEmail(string email)
  16. {
  17. QueryResult<QueryDto.OrderDto> lst = dp.QueryByEmail(email);
  18. return lst;
  19. }
  20. }

我们来看下UML:

SQLDispatcherContext用于保存当前函数的Region,这里保存的数据是瞬间的,随着函数的开始执行而有数据,随着函数的结束而被reset。

DBSelector是核心算法,用于根据配置文件算出不同的可选db,代码如下

  1. public class DBSelector
  2. {
  3. public static DB SelectDB(string sql, string region)
  4. {
  5. bool redirect2WritableDB = false;
  6. sql = sql.Trim().TrimStart('\r').TrimStart('\n');
  7. if (sql.IndexOf("UPDATE", StringComparison.OrdinalIgnoreCase) >= 0)
  8. redirect2WritableDB = true;
  9. if (sql.IndexOf("DELETE", StringComparison.OrdinalIgnoreCase) >= 0)
  10. redirect2WritableDB = true;
  11. if (sql.IndexOf("INSERT", StringComparison.OrdinalIgnoreCase) >= 0)
  12. redirect2WritableDB = true;
  13. if (sql.IndexOf("--WRITE", StringComparison.OrdinalIgnoreCase) == 0) //强制sql方式进入写db操作
  14. redirect2WritableDB = true;
  15.  
  16. if (redirect2WritableDB)
  17. return Config.SQLDispatcherConfiguration.WritableDB;
  18.  
  19. if (region == null || region.Length == 0) //from normal read dbs
  20. {
  21. int random = GenerateRandomNumber();
  22. int dbIndex = random % Config.SQLDispatcherConfiguration.ReadDBs.Count;
  23. return Config.SQLDispatcherConfiguration.ReadDBs[dbIndex];
  24. }
  25.  
  26. DedicatedRegion r = Config.SQLDispatcherConfiguration.DedicatedRegions.Find(t => t.Region.Equals(region, StringComparison.OrdinalIgnoreCase));
  27. if (r == null)
  28. throw new Exception("No such Dedicated Region Identifier.");
  29.  
  30. {
  31. int random = GenerateRandomNumber();
  32. int dbIndex = random % r.DBs.Count;
  33. return r.DBs[dbIndex];
  34. }
  35. }
  36.  
  37. private static int GenerateRandomNumber()
  38. {
  39. Random Random1 = new Random();
  40. //产生0到1000的随机数
  41. int i1 = Random1.Next(0, 1001);
  42. return i1;
  43. }
  44. }

SqlHelperCoordinator类只是简单的根据DBSelector算出的结果调度真正的SqlHelper来执行:

  1. public sealed class SqlHelperCoordinator
  2. {
  3. public static int ExecuteNonQuery(CommandType commandType, string commandText, params SqlParameter[] commandParameters)
  4. {
  5. string region = SQLDispatcherContext.GetCurrentContext().Region;
  6. DB db=DBSelector.SelectDB(commandText, region);
  7. return SqlHelper.ExecuteNonQuery(db.ConnectionString, commandType, commandText, commandParameters);
  8. }
  9. public static SqlDataReader ExecuteReader(CommandType commandType, string commandText, params SqlParameter[] commandParameters)
  10. {
  11. string region = SQLDispatcherContext.GetCurrentContext().Region;
  12. DB db = DBSelector.SelectDB(commandText, region);
  13. return SqlHelper.ExecuteReader(db.ConnectionString, commandType, commandText, commandParameters);
  14. }
  15. }

Console测试代码(记得打开Sql profile检测sql哦):

  1. static void Main(string[] args)
  2. {
  3. InstancePoolResolver.Register<OrderQueryServiceInterface, OrderQueryService>();
  4.  
  5. using (OrderQueryServiceInterface srv = InstancePoolResolver.Resolve<OrderQueryServiceInterface>())
  6. {
  7. while (true)
  8. {
  9. //Thread.Sleep(1000);
  10. Console.ReadKey();
  11.  
  12. QueryResult<Core.QueryService.QueryDto.OrderDto> lst=srv.QueryByFirstName("aaron", new CoreFramework.QueryService.PagingInfo() { PageIndex = 0, PageSize = 10, OrderByColumn = "FirstName", IsAscendingSort = true });
  13. lst.List.ForEach(t=>Console.WriteLine(t.FirstName));
  14.  
  15. srv.QueryByEmail("aaron");
  16. }
  17. }
  18. }

运行2次(关闭后再运行,因为缓存还没有好,bug)

就会看到:

被查询的数据库名正好落在xml配置文件的范围

代码下载

自省推动进步,视野决定未来。
心怀远大理想。
为了家庭幸福而努力。
用A2D科技,服务社会。
 
分类: AOP架构可扩展

读写分离子系统 - C# SQL分发子系统(ADO.NET,不支持EF)的更多相关文章

  1. 读写分离子系统 - C# SQL分发子系统 - Entity Framework支持

    A2D Framework增加了EF支持,加上原先支持ADO.NET: 支持EF方式 支持ADO.NET方式 这次来讲如何让Entity Framework变成nb的读写分离 1. 先设计EF模型, ...

  2. 读写分离子系统 - C# SQL分发子系统(目前只支持ADO.NET)

    这次介绍的这个框架只适用于中小项目,并且各个读写数据库结构是一致的情况,还要并且是写入数据库只有1台情况. 我们来看看这个子系统适用的场景: 我们来看这个子系统的配置文件: <?xml vers ...

  3. EF Core3.0+ 通过拦截器实现读写分离与SQL日志记录

    前言 本文主要是讲解EF Core3.0+ 通过拦截器实现读写分离与SQL日志记录 注意拦截器只有EF Core3.0+ 支持,2.1请考虑上下文工厂的形式实现. 说点题外话.. 一晃又大半年没更新技 ...

  4. ProxySQL 读写分离实践

    前言 ProxySQL是一个高性能的MySQL中间件,拥有强大的规则引擎.具有以下特性: 连接池,而且是 multiplexing 主机和用户的最大连接数限制 自动下线后端DB 延迟超过阀值 ping ...

  5. ProxySQL 配置详解及读写分离(+GTID)等功能说明 (完整篇)

    ProxySQL是灵活强大的MySQL代理层, 是一个能实实在在用在生产环境的MySQL中间件,可以实现读写分离,支持 Query 路由功能,支持动态指定某个 SQL 进行 cache,支持动态加载配 ...

  6. mysql读写分离(PHP类)

    mysql读写分离(PHP类) 博客分类: php mysql   自己实现了php的读写分离,并且不用修改程序 优点:实现了读写分离,不依赖服务器硬件配置,并且都是可以配置read服务器,无限扩展 ...

  7. 基于amoeba实现mysql数据库的读写分离/负载均衡

    一.Amoeba的简述:[来自百度百科]      Amoeba是一个以MySQL为底层数据存储,并对应用提供MySQL协议接口的proxy.它集中地响应应用的请求,依据用户事先设置的规则,将SQL请 ...

  8. ProxySQL+Mysql实现数据库读写分离实战

    ProxySQL介绍 ProxySQL是一个高性能的MySQL中间件,拥有强大的规则引擎.具有以下特性:http://www.proxysql.com/ 1.连接池,而且是multiplexing 2 ...

  9. ProxySQL实现Mysql读写分离 - 部署手册

    ProxySQL是一个高性能的MySQL中间件,拥有强大的规则引擎.ProxySQL是用C++语言开发的,也是percona推的一款中间件,虽然也是一个轻量级产品,但性能很好(据测试,能处理千亿级的数 ...

随机推荐

  1. Mediator - 中介者模式

    定义 用一个中介对象来封装一系列的对象的交互.中介者使各对象不须要显示地相互使用,从而使其耦合松散,并且能够独立的改变他们之间的交互. 案例 比方有一个图像界面,在界面上有一个输入框LineEdit, ...

  2. applet授权数字签名

    一.压缩你的class类文件为jar包 1.如果你的须要压缩的类文件存在的包为:cn.mbq.test1和cn.mbq.test2 2.进入你的classes文件夹,在DOS窗体中运行命令:jar c ...

  3. 健身小管家--android app源码

    把做了近一个月的android程序源码放出来,里面包括但不限于如下内容: 1. 简单的android项目结构 2. 通用的adapter,不再为每一个ListView都写一个adapter,只要用此一 ...

  4. MEF框架在Silverlight中应用(15)

    原文:MEF框架在Silverlight中应用(15) MEF框架在Silverlight中应用 代码下载 MEF框架是微软提供的一个插件框架.应用概括为一句话:输入,输出,组合.下面是具体在Silv ...

  5. jquery自己主动旋转的登录界面的背景代码登录页背景图

    在其他网站上看到比较爽Web登录界面.背景图片可以自己主动旋转. 介绍给大家.有兴趣的可以改改下来作为自己的系统登录界面. 如图: watermark/2/text/aHR0cDovL2Jsb2cuY ...

  6. 安卓CTS官方文档之兼容性测试套件简介-attach

    官方英文文档原文:https://source.android.com/compatibility/cts-intro.html Compatibility Test Suite  兼容性测试套件 H ...

  7. GitHub上整理

    GitHub上整理 技术站点 Hacker News:非常棒的针对编程的链接聚合网站 Programming reddit:同上 MSDN:微软相关的官方技术集中地,主要是文档类 infoq:企业级应 ...

  8. Java 之Integer相等比较

    1.问题提出 今天在和同事讨论问题的时候,无意间谈到了Integer对象的比较,先看下代码: package test; public class IntegerEqual { /** * @para ...

  9. [C++] 获取IE代理server的账号password

    非常多程序须要使用'浏览器设置'的代理server,IE设置的代理server有可能是须要账号password的.如何编程获取浏览器设置的代理server的账号password呢? InternetQ ...

  10. .net操作PDF的一些资源(downmoon收集)

    因为业务需要,搜集了一些.net操作pdf的一些资源,特在此分享. 1.如何从 Adobe 可移植文档格式 (PDF) 文件中复制文本和图形 http://support.microsoft.com/ ...