上一篇文章我写了在SSMS(SqlServer数据库管理工具)中如何配置主从复制,链接如下:
这篇文章记录下如何使用SqlSugar实现数据库的读写分离,增删改只操作主库,通过数据库的分发和订阅功能完成主库数据自动往从库同步。
下面代码实现了配置主库和从库的数据库链接,同时往主库新增一条记录。
using SqlSugar;
using SqlSugarStart.DbModels;
using System;
using System.Collections.Generic;
namespace SqlSugarStart
{
/// <summary>
/// 主从复制
/// 一个主库 负责数据的增删改 SqlSugarTest
/// 三个从库 负责数据的查询 SqlSugarTest_001、SqlSugarTest_002、SqlSugarTest_003
/// </summary>
public static class ZCFZ
{
public static void show()
{
try
{
SqlSugarClient sqlSugarClient = new SqlSugarClient(new ConnectionConfig
{
DbType = DbType.SqlServer,//要连接的数据库类型
ConnectionString = "server=.;uid=sa;pwd=123456;database=SqlSugarTest",//sqlsqver数据库链接字符串 (主库)
IsAutoCloseConnection = true,
InitKeyType = InitKeyType.Attribute,
//从库
SlaveConnectionConfigs = new List<SlaveConnectionConfig>() {
new SlaveConnectionConfig()
{
HitRate=10,ConnectionString="server=.;uid=sa;pwd=123456;database=SqlSugarTest_001"
},
new SlaveConnectionConfig()
{
HitRate=10,ConnectionString="server=.;uid=sa;pwd=123456;database=SqlSugarTest_002"
},
new SlaveConnectionConfig()
{
HitRate=10,ConnectionString="server=.;uid=sa;pwd=123456;database=SqlSugarTest_003"
}
}
});
//新增一条记录,往主库插入记录
sqlSugarClient.Insertable<Commodity>(new Commodity()
{
ProductId = 1,
CategoryId = 1,
Title = "测试数据库读写分离",
Price = 1,
Url = "测试数据库读写分离",
ImageUrl = "测试数据库读写分离"
}).ExecuteCommand();
}
catch (Exception)
{
throw;
}
}
}
}
执行后查询数据库
可以看到主库和从库数据都已经存在。
为了能够显示出数据查的从库,对三个从库的记录进行更新。
update [SqlSugarTest_001].[dbo].[Commodity] set ImageUrl ='测试数据库读写分离_001' where id = 3
update [SqlSugarTest_002].[dbo].[Commodity] set ImageUrl ='测试数据库读写分离_002' where id = 3
update [SqlSugarTest_003].[dbo].[Commodity] set ImageUrl ='测试数据库读写分离_003' where id = 3
在代码中循环查询刚才插入的ID=3的记录
//从库中查询数据
for (int i = 0; i < 10; i++)
{
Commodity commodity = sqlSugarClient.Queryable<Commodity>().Where(c => c.Id == 3).First();
Console.WriteLine(commodity.ImageUrl);
}
查询结果:
可以看到10次查询中,记录都是查询的从库。
上面提到,数据先是插入到主库,然后再同步到从库,数据同步的过程是需要时间的,下面演示下这个时间差到底有多长:
using SqlSugar;
using SqlSugarStart.DbModels;
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace SqlSugarStart
{
/// <summary>
/// 主从复制
/// 一个主库 负责数据的增删改 SqlSugarTest
/// 三个从库 负责数据的查询 SqlSugarTest_001、SqlSugarTest_002、SqlSugarTest_003
/// </summary>
public static class ZCFZ
{
public static void show()
{
try
{
SqlSugarClient sqlSugarClient = new SqlSugarClient(new ConnectionConfig
{
DbType = DbType.SqlServer,//要连接的数据库类型
ConnectionString = "server=.;uid=sa;pwd=123456;database=SqlSugarTest",//sqlsqver数据库链接字符串 (主库)
IsAutoCloseConnection = true,
InitKeyType = InitKeyType.Attribute,
//从库
SlaveConnectionConfigs = new List<SlaveConnectionConfig>() {
new SlaveConnectionConfig()
{
HitRate=10,ConnectionString="server=.;uid=sa;pwd=123456;database=SqlSugarTest_001"
},
new SlaveConnectionConfig()
{
HitRate=10,ConnectionString="server=.;uid=sa;pwd=123456;database=SqlSugarTest_002"
},
new SlaveConnectionConfig()
{
HitRate=10,ConnectionString="server=.;uid=sa;pwd=123456;database=SqlSugarTest_003"
}
}
});
//新增一条记录,往主库插入记录
sqlSugarClient.Insertable<Commodity>(new Commodity()
{
ProductId = 1,
CategoryId = 1,
Title = "测试主从复制延迟",
Price = 1,
Url = "测试主从复制延迟",
ImageUrl = "测试主从复制延迟"
}).ExecuteCommand();
bool isGoOn = true;//是否继续查询
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
while (isGoOn)
{
Commodity commodity = sqlSugarClient.Queryable<Commodity>().OrderBy(c => c.Id, OrderByType.Desc).First();
if (commodity.ImageUrl == "测试主从复制延迟")
{
stopwatch.Stop();
Console.WriteLine($"数据同步消耗时间:{stopwatch.ElapsedMilliseconds}毫秒");
isGoOn = false;//查询到新增的数据,说明数据已经同步完成,不再循环
Console.WriteLine("数据已经同步完成");
}
else
{
Console.WriteLine("数据还在同步中...");
}
}
}
catch (Exception)
{
throw;
}
}
}
}
执行结果:
可以看到数据经过一秒多的时间才被查询到。
针对这个问题,目前我还不知道最佳的解决方案,不过可以手动设置从主库中获取数据,下面演示下:
using SqlSugar;
using SqlSugarStart.DbModels;
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace SqlSugarStart
{
/// <summary>
/// 主从复制
/// 一个主库 负责数据的增删改 SqlSugarTest
/// 三个从库 负责数据的查询 SqlSugarTest_001、SqlSugarTest_002、SqlSugarTest_003
/// </summary>
public static class ZCFZ
{
public static void show()
{
try
{
SqlSugarClient sqlSugarClient = new SqlSugarClient(new ConnectionConfig
{
DbType = DbType.SqlServer,//要连接的数据库类型
ConnectionString = "server=.;uid=sa;pwd=123456;database=SqlSugarTest",//sqlsqver数据库链接字符串 (主库)
IsAutoCloseConnection = true,
InitKeyType = InitKeyType.Attribute,
//从库
SlaveConnectionConfigs = new List<SlaveConnectionConfig>() {
new SlaveConnectionConfig()
{
HitRate=10,ConnectionString="server=.;uid=sa;pwd=123456;database=SqlSugarTest_001"
},
new SlaveConnectionConfig()
{
HitRate=10,ConnectionString="server=.;uid=sa;pwd=123456;database=SqlSugarTest_002"
},
new SlaveConnectionConfig()
{
HitRate=10,ConnectionString="server=.;uid=sa;pwd=123456;database=SqlSugarTest_003"
}
}
});
//新增一条记录,往主库插入记录
sqlSugarClient.Insertable<Commodity>(new Commodity()
{
ProductId = 1,
CategoryId = 1,
Title = "测试主从复制延迟解决测试",
Price = 1,
Url = "测试主从复制延迟解决测试",
ImageUrl = "测试主从复制延迟解决测试"
}).ExecuteCommand();
bool isGoOn = true;//是否继续查询
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
while (isGoOn)
{
//默认去从库中查询数据
//设置IsDisableMasterSlaveSeparation为true,关闭主从分离开关,去主库查询
sqlSugarClient.Ado.IsDisableMasterSlaveSeparation = true;
Commodity commodity = sqlSugarClient.Queryable<Commodity>().OrderBy(c => c.Id, OrderByType.Desc).First();
if (commodity.ImageUrl == "测试主从复制延迟解决测试")
{
stopwatch.Stop();
Console.WriteLine($"数据同步消耗时间:{stopwatch.ElapsedMilliseconds}毫秒");
isGoOn = false;//查询到新增的数据,说明数据已经同步完成,不再循环
Console.WriteLine("数据已经同步完成");
}
else
{
Console.WriteLine("数据还在同步中...");
}
}
}
catch (Exception)
{
throw;
}
}
}
}
执行结果:
这次的查询比上次多了一个设置,关闭主从分离开关,去主库查询
这样就不会有数据查询延迟,但同时也破坏了读写分离的原则,目前还不知道这里应该怎么解决最好。