.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架构师谈:数据库分库分表.读写分离的原理实现,使用场景 为什么要分库分表和读写分离? 类似淘宝网这样的网站,海量数据的存储和访问成为了系统设计的瓶颈问题,日益增长的业务数据,无疑对 ...
随机推荐
- java中String类的使用
一.Strng类的概念 String类在我们开发中经常使用,在jdk1.8版本之前(包括1.8),String类的底层是一个char类型的数组,1.8版本之后是byte类型的数组,正是因为String ...
- 使用Eclipse创建Maven的JSP项目
使用Eclipse创建Maven的JSP项目 MyEclipse2015根本不行,试过各种解决方案都无济于事. 创建Maven项目 此时项目上有错,pom.xml有错. 修改Java版本 生成web. ...
- B 站今日黑白页是怎么实现的?
今天是2020年4月4日哀悼活动,不少相关站点都将网站全部变为灰色,以表示哀悼.以下为CSS代码.直接在*.css文件最前面加入. <!-- 置为灰色 --> <style type ...
- 03Python网络编程系列之服务端
# 这里边是一个定义了服务端的一系列函数,是Python网络编程这本书第七章的第一个例子.# 这是供后边函数进行调用了,然后我们来进行研究网络的单线程编程,多线程编程.异步网络编程等.# 导入网络编程 ...
- 安装seafile记录文档
安装yum-cron.iptables .关闭selinux yum -y install cronie yum -y install yum-cron systemctl start yu,-cro ...
- Java多线程中的虚假唤醒和如何避免
先来看一个例子 一个卖面的面馆,有一个做面的厨师和一个吃面的食客,需要保证,厨师做一碗面,食客吃一碗面,不能一次性多做几碗面,更不能没有面的时候吃面:按照上述操作,进行十轮做面吃面的操作. 用代码说话 ...
- PyQt(Python+Qt)学习随笔:使用实例方法赋值方式捕获事件
专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 在<第15.17节 PyQt(Python+ ...
- Python中的列表解析和列表推导是一回事吗?
列表解析和列表推导就是一个意思,只是从英文"list comprehension"翻译过来的不同翻译方法. 列表解析就是通过解析表达式从一个可迭代对象生成一个新的列表的Python ...
- 「Elasticsearch」SpringBoot快速集成ES
Elastic Search 的底层是开源库 Lucene.但是Lucene的使用门槛比较高,必须自己写代码去调用它的接口.而Elastic Search的出现正是为了解决了这个问题,它是 Lucen ...
- DokcerFile的添加及如何生成一个自定义镜像mycentos(四)
最近在学习Docker,用commit去生成一个镜像,但是生成后的镜像非常臃肿,所以去学习了一下DockerFile. 前提条件: 已在虚拟机中成功安装Docker 简单的理解可以如下图所示: Doc ...