目录
介绍
为什么要读写分离?
如何实现读写分离?
为什么一个主库多个从库?
是否有缺点?
如何解决延迟问题?
具体如何实现?
实现
SqlServer 实现
.NET Core MVC项目实现
Models层实现
如今,我们操作数据库一般用ORM框架
现在用.NET Core + EFCore + SqlServer 实现数据读写分离
降低数据库服务器的压力
1.一个主库多个从库
2.配置主库复制数据到从库
一般查询多于增删改,这就是我们常说的二八原则,20%操作是增删改,80%操作是查询
有延迟
比较及时性的数据还是通过主库查询
通过发布服务器,主库发布,而从库订阅,从而实现主从库
使用SqlServer 2019,新建一个主库,创建表,再通过本地发布创建发布,
然后通过本地订阅订阅主库,创建两个从库
项目结构
首先,在appsettings.json配置数据库连接字符串
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"EFCoreTestToRead": "Server=GREAMBWANG-DC\\MSSQLSERVER2019;Database=EFCoreTestToRead01;Trusted_Connection=True;,Server=GREAMBWANG-DC\\MSSQLSERVER2019;Database=EFCoreTestToRead02;Trusted_Connection=True;",
"EFCoreTestToWrite": "Server=GREAMBWANG-DC\\MSSQLSERVER2019;Database=EFCoreTest;Trusted_Connection=True;"
}
}
创建模型
public class UserInfo
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
创建上下文
public class EFCoreContext : DbContext
{
public EFCoreContext(string connectionString)
{
ConnectionString = connectionString;
//创建数据库
//Database.EnsureCreated();
}
private string ConnectionString { get; }
public DbSet UserInfo { get; set; }
///
/// 配置连接数据库
///
///
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
//base.OnConfiguring(optionsBuilder);
optionsBuilder.UseSqlServer(ConnectionString);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//base.OnModelCreating(modelBuilder);
//初始化数据
modelBuilder.Entity().HasData(new List()
{
new UserInfo() { Id = 1, Name = "哈哈", Age = 17 },
new UserInfo() { Id = 2, Name = "呵呵", Age = 18 },
new UserInfo() { Id = 3, Name = "嘻嘻", Age = 19 }
});
}
}
创建上下文工厂
读写枚举
public enum WriteAndReadEnum
{
Write,
Read
}
接口
public interface IDbContextFactory
{
EFCoreContext CreateContext(WriteAndReadEnum writeAndRead);
}
实现
在实现数据查询上,可以使用不同的策略,一般有随机策略,权重策略,轮询策略
随机策略:随机选择一个从库进行查询
权重策略:根据权重比例选择从库查询
轮询策略:根据顺序选择从库查询
public class DbContextFactory : IDbContextFactory
{
private IConfiguration Configuration { get; }
private string[] ReadConnectionStrings;
public DbContextFactory(IConfiguration configuration)
{
Configuration = configuration;
ReadConnectionStrings = Configuration.GetConnectionString("EFCoreTestToRead").Split(",");
}
public EFCoreContext CreateContext(WriteAndReadEnum writeAndRead)
{
string connectionString = string.Empty;
switch (writeAndRead)
{
case WriteAndReadEnum.Write:
connectionString = Configuration.GetConnectionString("EFCoreTestToWrite");
break;
case WriteAndReadEnum.Read:
connectionString = GetReadConnectionString();
break;
default:
break;
}
return new EFCoreContext(connectionString);
}
private string GetReadConnectionString()
{
/*
* 随机策略
* 权重策略
* 轮询策略
*/
//随机策略
string connectionString = ReadConnectionStrings[new Random().Next(0, ReadConnectionStrings.Length)];
return connectionString;
}
}
Models层完成
在Web层中
在Startup的ConfigureServices方法添加依赖注入
services.AddScoped();
操作
public class HomeController : Controller
{
private readonly ILogger _logger;
public IDbContextFactory DbContextFactory { get; }
public HomeController(ILogger logger,IDbContextFactory dbContextFactory)
{
_logger = logger;
DbContextFactory = dbContextFactory;
}
public IActionResult Index()
{
//写入操作
EFCoreContext writeContext = DbContextFactory.CreateContext(WriteAndReadEnum.Write);
writeContext.UserInfo.Add(new UserInfo() { Name = "AA", Age = 20 });
writeContext.SaveChanges();
//查询操作
EFCoreContext readContext = DbContextFactory.CreateContext(WriteAndReadEnum.Read);
UserInfo userInfo = readContext.UserInfo.OrderByDescending(u => u.Id).FirstOrDefault();
return View();
}
}
TO BE CONTINUED