1. 程式人生 > 實用技巧 >.NET Core + EFCore 實現資料讀寫分離

.NET Core + EFCore 實現資料讀寫分離

如今,我們操作資料庫一般用ORM框架

現在用.NET Core + EFCore +SqlServer實現資料讀寫分離

介紹

為什麼要讀寫分離?

降低資料庫伺服器的壓力

如何實現讀寫分離?

1.一個主庫多個從庫

2.配置主庫複製資料到從庫

為什麼一個主庫多個從庫?

一般查詢多於增刪改,這就是我們常說的二八原則,20%操作是增刪改,80%操作是查詢

是否有缺點?

有延遲

如何解決延遲問題?

比較及時性的資料還是通過主庫查詢

具體如何實現?

通過釋出伺服器,主庫釋出,而從庫訂閱,從而實現主從庫

實現

SqlServer實現

使用SqlServer 2019,新建一個主庫,建立表,再通過本地釋出建立釋出,

然後通過本地訂閱訂閱主庫,建立兩個從庫

.NET Core MVC專案實現

專案結構

首先,在appsettings.json配置資料庫連線字串

  1. {
  2. "Logging": {
  3. "LogLevel": {
  4. "Default": "Information",
  5. "Microsoft": "Warning",
  6. "Microsoft.Hosting.Lifetime": "Information"
  7. }
  8. },
  9. "AllowedHosts": "*",
  10. "ConnectionStrings": {
  11. "EFCoreTestToRead": "Server=GREAMBWANG-DC\\MSSQLSERVER2019;Database=EFCoreTestToRead01;Trusted_Connection=True;,Server=GREAMBWANG-DC\\MSSQLSERVER2019;Database=EFCoreTestToRead02;Trusted_Connection=True;",
  12. "EFCoreTestToWrite": "Server=GREAMBWANG-DC\\MSSQLSERVER2019;Database=EFCoreTest;Trusted_Connection=True;"
  13. }
  14. }

Models層實現

建立模型

  1. public class UserInfo
  2. {
  3. [Key]
  4. public int Id { get; set; }
  5. public string Name { get; set; }
  6. public int Age { get; set; }
  7. }

建立上下文

  1. public class EFCoreContext : DbContext
  2. {
  3. public EFCoreContext(string connectionString)
  4. {
  5. ConnectionString = connectionString;
  6. //建立資料庫
  7. //Database.EnsureCreated();
  8. }
  9. private string ConnectionString { get; }
  10. public DbSet<UserInfo> UserInfo { get; set; }
  11. /// <summary>
  12. /// 配置連線資料庫
  13. /// </summary>
  14. /// <param name="optionsBuilder"></param>
  15. protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
  16. {
  17. //base.OnConfiguring(optionsBuilder);
  18. optionsBuilder.UseSqlServer(ConnectionString);
  19. }
  20. protected override void OnModelCreating(ModelBuilder modelBuilder)
  21. {
  22. //base.OnModelCreating(modelBuilder);
  23. //初始化資料
  24. modelBuilder.Entity<UserInfo>().HasData(new List<UserInfo>()
  25. {
  26. new UserInfo() { Id = 1, Name = "哈哈", Age = 17 },
  27. new UserInfo() { Id = 2, Name = "呵呵", Age = 18 },
  28. new UserInfo() { Id = 3, Name = "嘻嘻", Age = 19 }
  29. });
  30. }
  31. }

建立上下文工廠

讀寫列舉

  1. public enum WriteAndReadEnum
  2. {
  3. Write,
  4. Read
  5. }

介面

  1. public interface IDbContextFactory
  2. {
  3. EFCoreContext CreateContext(WriteAndReadEnum writeAndRead);
  4. }

實現

在實現資料查詢上,可以使用不同的策略,一般有隨機策略,權重策略,輪詢策略

隨機策略:隨機選擇一個從庫進行查詢

權重策略:根據權重比例選擇從庫查詢

輪詢策略:根據順序選擇從庫查詢

  1. public class DbContextFactory : IDbContextFactory
  2. {
  3. private IConfiguration Configuration { get; }
  4. private string[] ReadConnectionStrings;
  5. public DbContextFactory(IConfiguration configuration)
  6. {
  7. Configuration = configuration;
  8. ReadConnectionStrings = Configuration.GetConnectionString("EFCoreTestToRead").Split(",");
  9. }
  10. public EFCoreContext CreateContext(WriteAndReadEnum writeAndRead)
  11. {
  12. string connectionString = string.Empty;
  13. switch (writeAndRead)
  14. {
  15. case WriteAndReadEnum.Write:
  16. connectionString = Configuration.GetConnectionString("EFCoreTestToWrite");
  17. break;
  18. case WriteAndReadEnum.Read:
  19. connectionString = GetReadConnectionString();
  20. break;
  21. default:
  22. break;
  23. }
  24. return new EFCoreContext(connectionString);
  25. }
  26. private string GetReadConnectionString()
  27. {
  28. /*
  29. * 隨機策略
  30. * 權重策略
  31. * 輪詢策略
  32. */
  33. //隨機策略
  34. string connectionString = ReadConnectionStrings[new Random().Next(0, ReadConnectionStrings.Length)];
  35. return connectionString;
  36. }
  37. }

Models層完成

在Web層中

在Startup的ConfigureServices方法新增依賴注入

services.AddScoped<IDbContextFactory, DbContextFactory>();

操作

  1. public class HomeController : Controller
  2. {
  3. private readonly ILogger<HomeController> _logger;
  4. public IDbContextFactory DbContextFactory { get; }
  5. public HomeController(ILogger<HomeController> logger,IDbContextFactory dbContextFactory)
  6. {
  7. _logger = logger;
  8. DbContextFactory = dbContextFactory;
  9. }
  10. public IActionResult Index()
  11. {
  12. //寫入操作
  13. EFCoreContext writeContext = DbContextFactory.CreateContext(WriteAndReadEnum.Write);
  14. writeContext.UserInfo.Add(new UserInfo() { Name = "AA", Age = 20 });
  15. writeContext.SaveChanges();
  16. //查詢操作
  17. EFCoreContext readContext = DbContextFactory.CreateContext(WriteAndReadEnum.Read);
  18. UserInfo userInfo = readContext.UserInfo.OrderByDescending(u => u.Id).FirstOrDefault();
  19. return View();
  20. }
  21. }