.Net 8.0之SQL Server读写分离的配置

本文详细描述了在.NET8.0环境下,使用EntityFrameworkCore(EFCore)配置SQLServer的读写分离策略,包括设置不同的数据库连接、DbContext的修改以及在API项目中的应用实例。
摘要由CSDN通过智能技术生成
1.背景

    在实际工作中,会有读写分离的场景。对于该类型场景,我们应该怎么处理了。最先考虑的肯定是配置不同的数据库连接,查询数据的就走 查询用的数据库A,增删改数据的就走 修改用的数据库B。专业点描述就是先将数据库配置发布订阅模式,实现了1主多从的模式,主数据库一般负责更新数据,从数据库会同步主数据库的数据过来。上面的A就是从数据库服务器,B就是主数据库服务器。

  本文介绍在.Net 8.0下,结合EFCore在项目中如何配置Sql Server读写分离。解决思路是在DBContext中去修改数据库连接,在具体使用DBContext查询数据或者新增数据时,指定具体的数据库配置去查询数据。

2.操作
2.1 准备一个web api项目

  这是我之前做的demo,我会以它为例子去讲解。

2.2 新增配置

打开配置文件appsettings.json,加入下列配置

"ConnectionStrings": {
  "WriteConnection": "Data Source=127.0.0.1;Initial Catalog=AdvancedCustomerDB_Init;Persist Security Info=True;User ID=sa;Password=*;Encrypt=False;TrustServerCertificate=true;",
  "ReadConnectionList": [
    "Data Source=127.0.0.1;Initial Catalog=AdvancedCustomerDB_Init_1;Persist Security Info=True;User ID=sa;Password=*;Encrypt=False;TrustServerCertificate=true;",
    "Data Source=127.0.0.1;Initial Catalog=AdvancedCustomerDB_Init_2;Persist Security Info=True;User ID=sa;Password=*;Encrypt=False;TrustServerCertificate=true;"
  ]
}
2.3 编写代码

 关键类DbContextFactory,专门生成DBContext

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using SimpleWebApi.Migration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SimpleWebApi.Business.Service.Interface
{
    public class DbContextFactory : IDbContextFactory
    {
        private DBConnectionOption _DBConnection = null;

        private DbContext _DbContext = null;

        public DbContextFactory(IOptionsMonitor<DBConnectionOption>
            optionsMonitor, DbContext dbContext)
        {
            _DBConnection = optionsMonitor.CurrentValue;
            _DbContext = dbContext;
        }

        public DbContext GetDbContext(WriteAndReadEnum writeAndRead)
        {
            switch (writeAndRead)
            {
                case WriteAndReadEnum.Write:
                    ToWrite();
                    break;
                case WriteAndReadEnum.Read:
                    ToRead();
                    break;
                default:
                    break;
            }

            return _DbContext;
        }

        private void ToWrite()
        {
            string conn = _DBConnection.WriteConnection; //主库连接
            this._DbContext = _DbContext.SetConnectionString(conn);
        }


        private void ToRead() 
        {
            string conn = string.Empty;

            int Count = _DBConnection.ReadConnectionList.Count;
            int index=new Random().Next(0, Count);
            conn = _DBConnection.ReadConnectionList[index];

           
            this._DbContext=_DbContext.SetConnectionString(conn);

        }

    }
}
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SimpleWebApi.Business.Service.Interface
{
    public interface IDbContextFactory
    {

        public DbContext GetDbContext(WriteAndReadEnum writeAndRead);

    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SimpleWebApi.Business.Service.Interface
{
    public enum WriteAndReadEnum
    {
        Write, 
        Read 

    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SimpleWebApi.Business.Service.Interface
{
    /// <summary>
    /// 读写数据库的数据库连接
    /// </summary>
    public class DBConnectionOption
    {
        public string WriteConnection { get; set; }   

        public List<string> ReadConnectionList { get; set; }    
    }
}

using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SimpleWebApi.Migration
{
    public static class DbContextExtension
    {
        public static DbContext SetConnectionString(this DbContext dbContext,string conn)
        {
            if (dbContext is AdvancedCustomerDbContext)
            {
                AdvancedCustomerDbContext context = (AdvancedCustomerDbContext)dbContext;
                return context.SetConnectionString(conn);
            }
            else
            {
                throw new Exception();
            }


        }

    }
}
2.4 改造原有代码

将BaseService文件,注入IDbContextFactory对象,并在每个方法中,加入数据操作的类型,比如是查询还是更新数据。

对于子类CommodityService等,里面的每个方法中,加入数据操作的类型,比如是查询还是更新数据。相关接口变动了参数的,也需要修改。此处不做具体介绍。

找到AdvancedCustomerDbContext。按照下图修改代码

打开Program.cs,加入下图代码

   #region EFCore支持读写分离
   builder.Services.AddTransient<IDbContextFactory, DbContextFactory>();
   builder.Services.Configure<DBConnectionOption>(builder.Configuration.GetSection("ConnectionStrings"));
  
   #endregion

ApiController代码如下:

using AutoMapper;
using Microsoft.AspNetCore.Mvc;
using SimpleWebApi.Business.Service.Interface;
using SimpleWebApi.Migration.Models;
using System.Linq.Expressions;

namespace SimpleWebApi.Controllers
{
    [ApiController]
    [Route("api/[controller]/[action]")]
    public class ApiController : ControllerBase
    {
        private readonly ILogger<ApiController> _logger;

        private ICommodityService _comService;
        private ICompanyInfoService _companyService;

        private IMapper _mapper;

        public ApiController(ILogger<ApiController> logger, ICommodityService comService, ICompanyInfoService companyService, IMapper mapper)
        {
            _logger = logger;
            _comService = comService;
            _companyService = companyService;
            _mapper = mapper;
        }

        [HttpGet]
        public IEnumerable<CommodityDTO> GetCommodity(int Id,int type=1)
        {
            WriteAndReadEnum typeDB = (WriteAndReadEnum)type;

            Expression<Func<Commodity, bool>> funcWhere = null;
            funcWhere = a => a.Id == Id;
            var commodityList = _comService.Query(funcWhere,typeDB);
            List<CommodityDTO> list = new List<CommodityDTO>();
            _mapper.Map<IQueryable<Commodity>, List<CommodityDTO>>(commodityList, list);

            return list;

        }

        [HttpGet]
        public CompanyInfoDTO GetCompanyInfo(int companyId)
        {
            var company = _companyService.GetCompany(companyId);
            CompanyInfoDTO dto = new CompanyInfoDTO();
            _mapper.Map<CompanyInfo, CompanyInfoDTO>(company, dto);

            return dto;

        }

        [HttpPost]
        public bool AddCommodity(CommodityDTO companyDto)
        {
            Commodity company = new Commodity();
            _mapper.Map<CommodityDTO, Commodity>(companyDto,company);
            var flag = _comService.AddCommodity(company);
            return flag;

        }
    }
}
2.5 代码执行

A.测试写数据

使用接口/api/Api/AddCommodity 新增数据。这接口应该是写主数据库AdvancedCustomerDB_Init,从数据库AdvancedCustomerDB_Init_1和AdvancedCustomerDB_Init_2不会马上有数据库(我做了限制)

查询数据库。发现数据已经成功插入到主数据库AdvancedCustomerDB_Init,且从数据库暂时没这条数据。

A.测试读数据

使用读接口 /api/Api/GetCommodity 查询刚刚新增的那条Id=6的数据。(做了限制。此时从数据没这个数据)

  可以明显看到,接口 没有返回数据吗,因为此时从数据库就是没这个数据的

修改参数type为0(1表示 从数据库查询,1表示  主数据库查询)

这么设置,是考虑到有时候数据查询要有即时性。所以直接指定从 主数据库查询数据。具体看实际情况的。

发现接口成功返回了数据。符合预期

3.结论

本文介绍了读写分离的设置。也是我自己理解的过程,我也上传了代码。请按需下载。至此,结束。

  • 23
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
.NET 8.0 的自动安装通常涉及到使用官方的安装程序或依赖于Windows更新系统,因为.NET Framework的更新通常是通过Windows Update进行管理的。如果你是在Windows 10或更新版本上,并且想要安装.NET 8,以下是一般的步骤: 1. **检查更新**: - 打开"设置" -> "更新和安全" -> "Windows Update",确保所有更新都已安装,包括KB4567975(这个包含.NET 8的安装组件)。 2. **通过Windows Store**: - 如果没有自动安装,你可以尝试在Microsoft Store中搜索.NET SDK并查看是否有.NET 8的可用版本。如果是Windows Insider Program成员,可能可以在预览版中找到。 3. **使用.NET SDK Installer**: - 官方的.NET SDK安装器可以从Microsoft的官方网站下载:https://dotnet.microsoft.com/download/dotnet/8.0,选择适合你的平台(如Windows x64或x86)并下载。 4. **命令行安装**: - 如果你想通过命令行快速安装,可以打开PowerShell作为管理员,然后运行以下命令: ``` dotnet restore --add-source https://api.nuget.org/v3/index.json dotnet tool install --global dotnet-sdk-8.0 ``` 这会安装最新的.NET 8 SDK工具。 5. **验证安装**: 安装完成后,你可以通过运行`dotnet --version`来检查是否已经安装了.NET 8.0。 **相关问题**: 1. Windows Update如何检查.NET 8的可用性? 2. 如何在命令行中确认安装的.NET SDK版本? 3. 如果安装过程中遇到问题,有哪些常见的解决方法?
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

laiger90

众筹一元加个菜~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值