经过一些调整和优化,4.3已经运行在生产环境,对于不久将会遇到的查询性能,读写分离需求列上日程
读写分离需求
对于一个数据库作了主从发布/订阅,主库为DB1,从库为DB2
所有写入通过DB1,所有查询通过DB2,当然也可以通过DB1
CRL内部实现
在CRL内部调用,请求读和请求写的方法会标记为Read或Write,然后再通过标记实现不同的数据库连接访问对象
如以下代码
1 /// <summary> 2 /// 返回动态对象的查询 3 /// </summary> 4 /// <param name="query"></param> 5 /// <returns></returns> 6 internal CallBackDataReader GetQueryDynamicReader(LambdaQueryBase query) 7 { 8 CheckTableCreated(query.__MainType); 9 var sql = ""; 10 query.FillParames(this); 11 sql = query.GetQuery(); 12 sql = _DBAdapter.SqlFormat(sql); 13 System.Data.Common.DbDataReader reader; 14 var compileSp = query.__CompileSp; 15 var db = GetDBHelper(AccessType.Read); 16 if (!compileSp) 17 { 18 if (query.TakeNum > 0) 19 { 20 db.AutoFormatWithNolock = false; 21 } 22 reader = db.ExecDataReader(sql); 23 } 24 else//生成储过程 25 { 26 string sp = CompileSqlToSp(_DBAdapter.TemplateSp, sql); 27 reader = db.RunDataReader(sp); 28 } 29 query.ExecuteTime = db.ExecuteTime; 30 ClearParame(); 31 return new CallBackDataReader(reader, null, sql); 32 }
GetDBHelper方法将此标记传到数据访问对象创建层
在程序启动处,以Global为例
1 protected void Application_Start(object sender, EventArgs e) 2 { 3 CRL.SettingConfig.UseReadSeparation = true;//启用主从读写分离 4 //配置数据连接 5 CRL.SettingConfig.GetDbAccess = (dbLocation) => 6 { 7 var obj = dbLocation.TagData; 8 if (dbLocation.ShardingDataBase != null)//按分库判断 9 { 10 if (dbLocation.ShardingDataBase.Name == "db1") 11 { 12 return WebTest.Code.LocalSqlHelper.TestConnection; 13 } 14 else 15 { 16 return WebTest.Code.LocalSqlHelper.TestConnection2; 17 } 18 } 19 else 20 { 21 //可按type区分数据库 22 var type2 = dbLocation.ManageType; 23 if (type2 == typeof(Code.MongoDBTestManage)) 24 { 25 return Code.LocalSqlHelper.MongoDB; 26 } 27 if(dbLocation.AccessType== CRL.AccessType.Read)//区分读写 28 { 29 return Code.LocalSqlHelper.TestConnection2; 30 } 31 return WebTest.Code.LocalSqlHelper.TestConnection; 32 } 33 }; 34 35 }
这样就实现了在逻辑调用上实现了读写分离
实际调用
启用主从读写分离
CRL.SettingConfig.UseReadSeparation = true;
更改数据
var item = Code.ProductDataManage.Instance.QueryItem(2); item.ProductName = "更改主库数据为" + DateTime.Now.Second; Code.ProductDataManage.Instance.Update(item);
DB1数据被更改
查询数据
var item = Code.ProductDataManage.Instance.QueryItem(2); Response.Write("从库数据2为" + item.ProductName);
查询出DB2的数据
事务问题
由于主从复制可能存在延迟,在事务中可不想查到脏数据,或者数据在事务中被更改
因此,在事务内需要由主库查询
在CRL事务范围内的查询,都默认为主库
此功能测试代码见文档/Page/ReadSeparation.aspx
最新源码见文章底部签名