博客
关于我
读写分离子系统 - C# SQL分发子系统(目前只支持ADO.NET)
阅读量:727 次
发布时间:2019-03-22

本文共 5458 字,大约阅读时间需要 18 分钟。

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

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

 

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

Server=.;Database=d1;User Id=sa;Password=111111;
//唯一的主数据库(写入DB)
Server=.;Database=d2;User Id=sa;Password=111111;
//这些是普通的对等的读数据库,只是做了些普通索引优化
Server=.;Database=d3;User Id=sa;Password=111111;
//同上
Server=.;Database=d4;User Id=sa;Password=111111;
//同上
Optimization_Sales
                //这个区域代表所列出来的DB是专门针对销售报表优化索引的数据库
Server=.;Database=d5;User Id=sa;Password=111111;
Server=.;Database=d6;User Id=sa;Password=111111;
Optimization_HR
                  //这样的专门Region可以有多个区域
Server=.;Database=d7;User Id=sa;Password=111111;

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

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

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

 

 我们来看下UML:

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

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

public class DBSelector    {        public static DB SelectDB(string sql, string region)        {            bool redirect2WritableDB = false;            sql = sql.Trim().TrimStart('\r').TrimStart('\n');            if (sql.IndexOf("UPDATE", StringComparison.OrdinalIgnoreCase) >= 0)                redirect2WritableDB = true;            if (sql.IndexOf("DELETE", StringComparison.OrdinalIgnoreCase) >= 0)                redirect2WritableDB = true;            if (sql.IndexOf("INSERT", StringComparison.OrdinalIgnoreCase) >= 0)                redirect2WritableDB = true;            if (sql.IndexOf("--WRITE", StringComparison.OrdinalIgnoreCase) == 0)    //强制sql方式进入写db操作                redirect2WritableDB = true;            if (redirect2WritableDB)                return Config.SQLDispatcherConfiguration.WritableDB;            if (region == null || region.Length == 0)       //from normal read dbs            {                int random = GenerateRandomNumber();                int dbIndex = random % Config.SQLDispatcherConfiguration.ReadDBs.Count;                return Config.SQLDispatcherConfiguration.ReadDBs[dbIndex];            }            DedicatedRegion r = Config.SQLDispatcherConfiguration.DedicatedRegions.Find(t => t.Region.Equals(region, StringComparison.OrdinalIgnoreCase));            if (r == null)                throw new Exception("No such Dedicated Region Identifier.");            {                int random = GenerateRandomNumber();                int dbIndex = random % r.DBs.Count;                return r.DBs[dbIndex];            }        }        private static int GenerateRandomNumber()        {            Random Random1 = new Random();            //产生0到1000的随机数            int i1 = Random1.Next(0, 1001);            return i1;        }    }

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

public sealed class SqlHelperCoordinator    {        public static int ExecuteNonQuery(CommandType commandType, string commandText, params SqlParameter[] commandParameters)        {            string region = SQLDispatcherContext.GetCurrentContext().Region;            DB db=DBSelector.SelectDB(commandText, region);            return SqlHelper.ExecuteNonQuery(db.ConnectionString, commandType, commandText, commandParameters);        }        public static SqlDataReader ExecuteReader(CommandType commandType, string commandText, params SqlParameter[] commandParameters)        {            string region = SQLDispatcherContext.GetCurrentContext().Region;            DB db = DBSelector.SelectDB(commandText, region);            return SqlHelper.ExecuteReader(db.ConnectionString, commandType, commandText, commandParameters);        }    }

 

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

static void Main(string[] args)        {            InstancePoolResolver.Register
(); using (OrderQueryServiceInterface srv = InstancePoolResolver.Resolve
()) { while (true) { //Thread.Sleep(1000); Console.ReadKey(); QueryResult
lst=srv.QueryByFirstName("aaron", new CoreFramework.QueryService.PagingInfo() { PageIndex = 0, PageSize = 10, OrderByColumn = "FirstName", IsAscendingSort = true }); lst.List.ForEach(t=>Console.WriteLine(t.FirstName)); srv.QueryByEmail("aaron"); } } }

 

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

就会看到:

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

 

 

 

转载地址:http://dckwk.baihongyu.com/

你可能感兴趣的文章
解决 matplotlib 中文显示乱码的问题
查看>>
解决打开 json 文件中文乱码的问题
查看>>
计算机网络基础:DHCP服务的部署
查看>>
计算机网络基础:DNS 部署与安全
查看>>
计算机网络基础:NAT 网络地址转换
查看>>
计算机网络基础:PKI(公钥基础设施)
查看>>
计算机网络基础:VLAN(虚拟局域网)
查看>>
计算机网络基础:文件共享服务器(注册表更改)
查看>>
计算机网络基础:用户和组管理
查看>>
计算机网络基础:简单渗透
查看>>
计算机网络模型-TCP/IP协议簇
查看>>
基于Arduino的ESP32-S3 + OLED(4pin)的文字取模
查看>>
基于Arduino的ESP32-S3 +光敏传感器(4pin)
查看>>
基于Arduino的ESP32-S3 + 1.3寸OLED(4pin)
查看>>
基于Arduino的ESP32-S3连接OneNET云平台实战指南(二)——Token生成
查看>>
基于Arduino的ESP32-S3连接OneNET云平台实战指南(四)——ESP32-S3连接OneNET云平台的订阅主题与发布主题、消息(数据流)
查看>>
基于Arduino的ESP32-S3 + HCSR04(4pin)超声波传感器
查看>>
基于Arduino的ESP32-S3 +DS18B20(3pin)
查看>>
基于任意单片机的继电器模块应用全解析
查看>>
基于Arduino的ESP32-S3 + 水浊度传感器
查看>>