.NET+SqlServer 实现数据读写分离
如今,我们操作数据库一般用ORM框架
现在用.NET Core + EFCore + SqlServer 实现数据读写分离
介绍
为什么要读写分离?
降低数据库服务器的压力
如何实现读写分离?
1.一个主库多个从库
2.配置主库复制数据到从库

为什么一个主库多个从库?
一般查询多于增删改,这就是我们常说的二八原则,20%操作是增删改,80%操作是查询
是否有缺点?
有延迟
如何解决延迟问题?
比较及时性的数据还是通过主库查询
具体如何实现?
通过发布服务器,主库发布,而从库订阅,从而实现主从库

实现
SqlServer 实现
1.使用SqlServer 2019,新建一个主库,创建表,再通过本地发布创建发布,
然后通过本地订阅订阅主库,创建两个从库

2.配置AlwaysOn高可用性

https://www.cnblogs.com/chenmh/p/4484176.html
.NET Core MVC项目实现
项目结构

首先,在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;"
}
}
Models层实现
创建模型
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> UserInfo { get; set; } /// <summary>
/// 配置连接数据库
/// </summary>
/// <param name="optionsBuilder"></param>
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
//base.OnConfiguring(optionsBuilder);
optionsBuilder.UseSqlServer(ConnectionString); } protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//base.OnModelCreating(modelBuilder); //初始化数据
modelBuilder.Entity<UserInfo>().HasData(new List<UserInfo>()
{
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);
}
实现
在实现数据查询上,可以使用不同的策略,一般有随机策略,权重策略,轮询策略
随机策略:随机选择一个从库进行查询
权重策略:根据权重比例选择从库查询
轮询策略:根据顺序选择从库查询
Models层完成
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;
}
}
在Web层中
在Startup的ConfigureServices方法添加依赖注入
services.AddScoped<IDbContextFactory, DbContextFactory>();
操作
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger; public IDbContextFactory DbContextFactory { get; } public HomeController(ILogger<HomeController> 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();
}
}
总结
sqlserver读写分离后,读库和主库会有一定时间的延迟,当业务逻辑是增加记录后马上刷新列表之类的逻辑时
alwayson ?
其实这个延迟一般情况下不会太大, 一般几十ms 到 几百 ms. 也可以在增加记录之后 Thread.Sleep(1000) 休眠一秒, 然后再刷新列表, 问题不大的。
特别重要的(关系到钱)的业务, 就只能直接读主库了。
要是不容许有不一致性,那你就别分离了。
但是也可以 业务逻辑是增加记录后马上刷新列表之类的逻辑时-->新增成功之后将数据添加到本地集合(BindingList/ObservableCollection)这样能将结果通知到UI列表显示,而不是再从新读取全部数据。
实际上读写分离相当程度上是增加了问题、增加了困难,而不是减少了问题。真正应该首先做到的是,尽量在逻辑中避免使用事务概念、甚至避免使用关系数据库,尽量将面向数据库增删改查的程序改为面向(几百万)微服务的并发程序。然而很多人没有这方面的理解,认为把数据库分库分表读写分离这类“优化”最简单,所以一味地浪费精力在看似最简单实则已经逐步脱离时代的优化概念上。
分离数据库不是什么好主意,甚至可以说是“坑爹”的。现在的大规模高性能的程序,实际上是去掉增删改查数据库层概念,而是面向全局一致性分布式数据缓存层来编程。
高性能系统是去低级的数据库层,而是使用中间件层,也就是在后台业务逻辑处理中也要至少三层设计。
具备维护功能的代码本身应该是读写在写的数据库上,而不是写在写数据库,而读在读数据库
.NET+SqlServer 实现数据读写分离的更多相关文章
- Python3 实现数据读写分离设计
前言 首先读写分离可以保证数据库的稳定,简单的说就是当网站访问量大时,读写都在一个库,很有可能会出现脏数据的情况,如果采取阻塞似操作,那么用户体验就会变得更差. 而且目前大多数网站的读写是失衡的,以淘 ...
- 查看SQL Server数据读写分离,并设置读写分离
1. 查看读写分离脚本,直接执行以下脚本: select name,is_read_committed_snapshot_on from sys.databases 执行结果列表中,name表示数据库 ...
- sqlserver实现数据库读写分离介绍
对于负载均衡,笔者经常接触的当属Oracle的负载均衡机制.下面我们重点介绍Sql Server 2005是如何实现负载均衡的,感兴趣的朋友可以参考下哈 Internet的规模每一百天就会增长一倍,客 ...
- Mycat实现Mysql数据库读写分离
Linux和Windows环境下搭建Mycat数据读写分离 前提需要:1.服务器装有JVM虚拟机,就是JDK.2.两个Mysql数据库已经实现主从复制,参考:https://www.cnblogs.c ...
- Amoeba读写分离(MySQL)
实验操作环境: centos服务器 三台机器 role: 192.168.189.129 master-主 192.168.189.130 master-从 192.168.189.131 ...
- LAMP企业架构读写分离
1.1 LAMP企业架构读写分离 LAMP+Discuz+Redis缓解了MYSQL的部分压力,但是如果访问量非常大,Redis缓存中第一次没有缓存数据,会导致MYSQL数据库压力增大,此时可以基于 ...
- 三十五.MySQL读写分离 MySQL多实例 、MySQL性能调优
1.实现MySQL读写分离 搭建一主一从结构 配置maxscale代理服务器 测试分离配置 1.1 搭建一主一从结构 192.168.4.51 主 192.168.4.52 从 测试OK 1. ...
- 使用Adivisor配置增强处理,来实现数据库读写分离
一.先写一个demo来概述Adivisor的简单使用步骤 实现步骤: 1.通过MethodBeforeAdivice接口实现前置增强处理 public class ServiceBeforeAdvis ...
- 阿里P8架构师谈:数据库分库分表、读写分离的原理实现,使用场景
本文转载自:阿里P8架构师谈:数据库分库分表.读写分离的原理实现,使用场景 为什么要分库分表和读写分离? 类似淘宝网这样的网站,海量数据的存储和访问成为了系统设计的瓶颈问题,日益增长的业务数据,无疑对 ...
随机推荐
- 【电子取证:抓包篇】Fiddler 抓包配置与数据分析(简)
Fiddler 抓包配置与分析(简) 简单介绍了Fiddler抓包常用到的基础知识,看完可以大概明白怎么分析抓包数据 ---[suy999] Fiddler 抓包工具,可以将网络传输发送与接受的数 ...
- Luogu P2656 采蘑菇
尽管是缩点的习题,思路也是在看了题解后才明白的. 首先,每个强连通分量内的点都是一定互通的,也就是可以完全把这里面的边都跑满,摘掉所有能摘的蘑菇.那么,考虑给每一个强连通分量化为的新点一个点权,代表摘 ...
- C语言基础知识:几种特殊的函数宏封装方式
函数宏介绍 函数宏,即包含多条语句的宏定义,其通常为某一被频繁调用的功能的语句封装,且不想通过函数方式封装来降低额外的弹栈压栈开销. 函数宏本质上为宏,可以直接进行定义,例如: #define INT ...
- 树莓派4b 安装最新wiringpi库
树莓派4自带的wiringPi库默认是2.50,无法映射到gpio,所以需要更新到2.52才能与树莓派映射: 1. 安装自带的wiringPi库 $ Sudo apt-get install wiri ...
- 冲刺随笔——Day_One
这个作业属于哪个课程 软件工程 (福州大学至诚学院 - 计算机工程系) 这个作业要求在哪里 团队作业第五次--Alpha冲刺 这个作业的目标 团队进行Alpha冲刺 作业正文 正文 其他参考文献 无 ...
- 为什么SimpleDateFormat不是线程安全的?
一.前言 日期的转换与格式化在项目中应该是比较常用的了,最近同事小刚出去面试实在是没想到被 SimpleDateFormat 给摆了一道... 面试官:项目中的日期转换怎么用的?SimpleDateF ...
- Apache Flink 如何正确处理实时计算场景中的乱序数据
一.流式计算的未来 在谷歌发表了 GFS.BigTable.Google MapReduce 三篇论文后,大数据技术真正有了第一次飞跃,Hadoop 生态系统逐渐发展起来. Hadoop 在处理大批量 ...
- (十八)面向流水线的设计:CPU的一心多用
一.单指令周期 由前可知,一条CPU指令的执行有三个步骤:指令读取.指令译码.指令执行.由于这个过程受CPU时钟的控制,如果我们将这个过程安排在一个CPU时钟周期内执行,这种设计思路就叫单 ...
- PyQt(Python+Qt)学习随笔:Qt Designer中部件的autoFillBackground属性
autoFillBackground属性可以确认部件背景是否自动填充,如果自动填充,Qt会在调用Paint事件之前填充部件的背景.使用的颜色由部件调色板中的QPalette.window 角色定义(关 ...
- PyQt(Python+Qt)学习随笔:在父窗口中弹出子窗口无法显现的问题
在学习和测试PyQt相关部件功能的时候,老猿经常是不同的窗口新建一个类,再新建一个Application来使用这个窗口类进行测试. 为了减少应用框架代码的重复开发,老猿决定采用主窗口叠加测试窗口的模式 ...