.NET Core + EFCore 實現資料讀寫分離
阿新 • • 發佈:2020-12-07
如今,我們操作資料庫一般用ORM框架
現在用.NET Core + EFCore +SqlServer實現資料讀寫分離
介紹
為什麼要讀寫分離?
降低資料庫伺服器的壓力
如何實現讀寫分離?
1.一個主庫多個從庫
2.配置主庫複製資料到從庫
為什麼一個主庫多個從庫?
一般查詢多於增刪改,這就是我們常說的二八原則,20%操作是增刪改,80%操作是查詢
是否有缺點?
有延遲
如何解決延遲問題?
比較及時性的資料還是通過主庫查詢
具體如何實現?
通過釋出伺服器,主庫釋出,而從庫訂閱,從而實現主從庫
實現
SqlServer實現
使用SqlServer 2019,新建一個主庫,建立表,再通過本地釋出建立釋出,
然後通過本地訂閱訂閱主庫,建立兩個從庫
.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
- {
- [ ]
- 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);
- }
實現
在實現資料查詢上,可以使用不同的策略,一般有隨機策略,權重策略,輪詢策略
隨機策略:隨機選擇一個從庫進行查詢
權重策略:根據權重比例選擇從庫查詢
輪詢策略:根據順序選擇從庫查詢
- 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<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();
- }
- }