分享好友 系统运维首页 频道列表

SQL Server、MySQL主从搭建,EF Core读写分离代码实现

服务器其它  2023-02-07 19:530

一、SQL Server的主从复制搭建

1.1、SQL Server主从复制结构图

SQL Server的主从通过发布订阅来实现

1.2、基于SQL Server2016实现主从

新建一个主库“MyDB”


建一个表"SysUser"测试

CREATE TABLE [dbo].[SysUser](
	[Id] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
	[UserName] [varchar](50) NOT NULL,
	[Account] [varchar](20) NOT NULL,
	[Password] [varchar](100) NOT NULL,
	[Phone] [varchar](50) NOT NULL,
	[CreateTime] [datetime] NOT NULL,
 CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED 
(
	[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

搭建发布服务器

复制》配置分发

这里创建一个自己的路径,共享文件夹

分发数据库

发布服务器


然后下一步完成

启用代理

服务确认一下登陆权限

到这里发布服务器就建好了。

发布
发布就是把主库的数据或操作发布到发布服务器

现在主库里录入了两条数据

新建发布

选择发布的数据库

发布类型

这里有几种不同发布方式,根据自己业务场景选择,互联网一般是事务发布,有操作就同步。

选择同步的表

一直下一步到这里,勾选初始化订阅

代理安全性

下一步

发布名称

完成

这时候在上面设的发布服务器的共享文件夹中能看到有发布文件了

创建订阅

新建一个从库“MyDb_Copy”,为一个没创建表的空库

新建订阅

选择订阅的发布

选择推送方式(发布服务器主动推送),还是拉取方式(从库服务器拉取方式),一个从库选推送,多个从库选择拉取方式

选择订阅数据库

分发代理安全性

一直下一步,直到完成!

验证

看从库数据同步过来了

主库增加一条数据

从库看到也同步了

到这里SQL Server2016的主从复制就完成了!

二、MySQL的主从复制搭建

2.1、MySQL主从复制结构图

主库把增删查改的操作写入到binlog日志。

从库开启两个线程,一个IO线程,负责读取binlog日志到relay日志。一个SQL线程从relay日志读取数据写入从库DB

2.2、基于Docker搭建MySQL的主从

拉取镜像

docker pull mysql:5.7

准备两个文件,主库mysqld.cnf,上传到目录 /home/mysql/master

[mysqld]
pid-file	= /var/run/mysqld/mysqld.pid
socket		= /var/run/mysqld/mysqld.sock
datadir		= /var/lib/mysql
#log-error	= /var/log/mysql/error.log
# By default we only accept connections from localhost
#bind-address	= 127.0.0.1
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
log-bin=mysql-bin
#id不要重复
server-id=11

从库mysald.cnf,上传到目录 /home/mysql/slave

[mysqld]
pid-file	= /var/run/mysqld/mysqld.pid
socket		= /var/run/mysqld/mysqld.sock
datadir		= /var/lib/mysql
#log-error	= /var/log/mysql/error.log
# By default we only accept connections from localhost
#bind-address	= 127.0.0.1
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
#id不重复
server-id=22
#从库不需要事务,改MyISAM快些
default-storage-engine=MyISAM 

创建主库容器

docker run --name mysql-master -p 3307:3306 -v /home/mysql/master:/etc/mysql/mysql.conf.d -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7

创建从库容器

 docker run --name mysql-slave -p 3308:3306 -v /home/mysql/slave:/etc/mysql/mysql.conf.d -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7

用连接工具连接上数据库,这里用DBeaver

配置主服务

首先,进入容器:

[root@localhost ~]# docker exec -it mysql-master /bin/bash
bash-4.2# 

链接MySQL

bash-4.2# mysql -u root -p123456
mysql> 

修改 root 可以通过任何客户端连接

mysql> ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
Query OK, 0 rows affected (0.00 sec)

mysql> 

重启Master服务器

mysql> exit
Bye
bash-4.2# exit
exit
[root@localhost ~]# docker restart mysql-master
mysql-master
[root@localhost ~]#

再次进入master容器

docker exec -it mysql-master /bin/bash

连接 MySQL

mysql -u root -p123456

查看数据库状态:


mysql>  show master status;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000005 |      154 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)

mysql>

把File的值“mysql-bin.000005”和 Position的值154记录下来

配置从服务器

首先,进入容器:

docker exec -it mysql-slave1 /bin/bash

连接 MySQL

mysql -u root -p123456

修改 root 可以通过任何客户端连接(默认root用户可以对从数据库进行编辑的)

ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';

配置从同步主服务数据,执行如下SQL

change master to
master_host='192.168.101.20',
master_user='root',
master_log_file='mysql-bin.000005',
master_log_pos=154,
master_port=3307,
master_password='123456';
  • master_log_file='mysql-bin.000005' 上面主库记录下来的值
  • master_log_pos=154 上面主库记录下来的值

启动slave服务

mysql>start slave;

查看slave状态

show slave status \G;

验证主从库搭建结果

主库创建数据库

刷新从库,也把数据库同步过来了

主库创建一张表

CREATE TABLE MyDB.sys_user (
	id int auto_increment NOT NULL,
	user_name varchar(150) NOT NULL,
	account varchar(20) NOT NULL,
	password varchar(100) NOT NULL,
	phone varchar(50) NOT NULL,
	create_time DATETIME NOT NULL,
	CONSTRAINT sys_user_PK PRIMARY KEY (id)
)
ENGINE=InnoDB
DEFAULT CHARSET=latin1
COLLATE=latin1_swedish_ci
AUTO_INCREMENT=1;

从库也同步了

主库插入数据,从库也能同步。

到这里,MySQL的主从搭建就完成了!

三、EF Core代码读写分离实现

这里用.NET6 +EF Core6.0 +SQLServer演示。

建一个.NET6的web程序

安装NuGet包

Microsoft.EntityFrameworkCore(6.0.7)
Microsoft.EntityFrameworkCore.SqlServer(6.0.7)

appsetting.json增加 ConnectinStrings节点

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "WriteConnection": "Data Source=.;Database=MyDB;User ID=sa;Password=123456",
    "ReadConnection": "Data Source=.;Database=MyDB_Copy;User ID=sa;Password=123456"
  }
}

增加一个类DBConnectionOption.cs来接收连接配置

  public class DBConnectionOption
    {
        public string WriteConnection { get; set; }
        public string ReadConnection { get; set; }
    }

增加一个类SysUser.cs来对应数据库表SysUser实体

    public class SysUser
    {
        public int Id { get; set; }
        public string UserName { get; set; }
        public string Account { get; set; }
        public string Password { get; set; }
        public string Phone { get; set; }
        public DateTime CreateTime { get; set; }
    }

增加一个类MyDBContext.cs来访问数库上下文

  public class MyDBContext : DbContext
    {
        private DBConnectionOption _readWriteOption;
        public MyDBContext(IOptionsMonitor<DBConnectionOption> options)
        {
            _readWriteOption = options.CurrentValue;
        }

        public DbContext ReadWrite()
        {
            //把链接字符串设为读写(主库)
            this.Database.GetDbConnection().ConnectionString = this._readWriteOption.WriteConnection;
            return this;
        }
        public DbContext Read()
        {
            //把链接字符串设为之读(从库)
            this.Database.GetDbConnection().ConnectionString = this._readWriteOption.ReadConnection;
            return this;
        }
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(this._readWriteOption.WriteConnection); //默认主库
        }
        public DbSet<SysUser> SysUser { get; set; }
    }

增加一个类DbContextExtend.cs来扩展上下文修改连接字符串

  /// <summary>
    /// 拓展方法
    /// </summary>
    public static class DbContextExtend
    {
        /// <summary>
        /// 只读
        /// </summary>
        /// <param name="dbContext"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static DbContext Read(this DbContext dbContext)
        {
            if (dbContext is MyDBContext)
            {
                return ((MyDBContext)dbContext).Read();
            }
            else
                throw new Exception();
        }
        /// <summary>
        /// 读写
        /// </summary>
        /// <param name="dbContext"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static DbContext ReadWrite(this DbContext dbContext)
        {
            if (dbContext is MyDBContext)
            {
                return ((MyDBContext)dbContext).ReadWrite();
            }
            else
                throw new Exception();
        }
    }

修改Program.cs,增加

builder.Services.Configure<DBConnectionOption>(builder.Configuration.GetSection("ConnectionStrings"));//注入多个链接
builder.Services.AddTransient<DbContext, MyDBContext>();

验证
在HomeController的Index方法里实现读写分离操作

        public IActionResult Index()
        {

            //新增-------------------
            SysUser user = new SysUser()
            {
                UserName="李二狗",
                Account="liergou",
                Password=Guid.NewGuid().ToString(),
                Phone="13345435554",
                CreateTime=DateTime.Now
            };

            Console.WriteLine($"新增,当前链接字符串为:{_dbContext.Database.GetDbConnection().ConnectionString}");
              _dbContext.ReadWrite().Add(user);
              _dbContext.SaveChanges();

            //只读--------------------------------
           var dbContext = _dbContext.Read();
         var users= _dbContext.Read().Set<SysUser>().ToList();
            Console.WriteLine($"读取SysUser,数量为:{users.Count},当前链接字符串为:{_dbContext.Database.GetDbConnection().ConnectionString}");

            return View();
        }

执行结果:

查看数据库,新增的数据也查入成功了。

这里读程序读写分离也完成了!

有没有细心的朋友发现读的时候日志只显示读到了3条记录,而上面一共有4条记录。

原因是主从同步会有延迟,从库没那么快同步到数据,一般都有个0.几到1秒的延迟,这个可以调优,这里就不说多内容了,有兴趣的可以去查资料操作一下。

到这里全部就完成了!

源码地址:https://github.com/weixiaolong325/EFCoreReadWriteSeparate

查看更多关于【服务器其它】的文章

展开全文
相关推荐
反对 0
举报 0
评论 0
图文资讯
热门推荐
优选好物
更多热点专题
更多推荐文章
ORACLE 分页SQL
这个sql的分页很简单,但是由于十分常用,且通常用于查询大量数据的情况。SELECT * FROM(        SELECT A.*,ROWNUM RN        FROM                     (SELECT * FROM TABLE_XX ) A        WHERE ROWNUM=20)  TL WHERE RN =11 

0评论2023-02-07455

代码中批量执行Oracle SQL语句
  今天在写一个工具(winform),作用是批量的INSERT OR  UPDATE ORACLE数据库中的一个表。  执行的时候老是报错“[911] ORA-00911: invalid character”  我把SQL语句拷贝出来放到PL SQL中去执行,又是对的,因为测试时正好就一条语句,而且我生成语

0评论2023-02-07904

ORM之Dapper操作Sql Server和MySql数据库
1.为什么选择Dapper1)轻量。2)速度快。Dapper的速度接近与IDataReader,取列表的数据超过了DataTable。3)支持多种数据库。Dapper可以在所有Ado.net Providers下工作,包括sqlite, sqlce, firebird, oracle, MySQL, PostgreSQL and SQL Server4)可以映射一对一

0评论2023-02-07817

MySQL同步故障:" Slave_SQL_Running:No" 两种解决办法
进入slave服务器,运行:mysql show slave status\G         .......             Relay_Log_File: localhost-relay-bin.000535              Relay_Log_Pos: 21795072      Relay_Master_Log_File: localhost-bin

0评论2023-02-07815

mysql数据库: 用户管理、pymysql使用、sql注入
本文目录:一、用户管理二、pymysql增删改查三、sql注入攻击  数据安全非常重要 不可能随便分配root账户应该按照不同开发岗位分配不同的账户和权限mysql中 将于用户相关的数据放在mysql库user -db -tables_priv - columns_priv如果用户拥有对所有库的访问权

0评论2023-02-07555

获得某个月的天数(java, mysql, oracle)
java方式:Calendar   cal   =   Calendar.getInstance();  cal.set(Calendar.YEAR,year);  cal.set(Calendar.MONTH,month+1);//2月  int   maxDate   =   cal.getActualMaximum(Calendar.DATE);mysql方式:"SELECT day(LAST_DAY(‘2007-04

0评论2023-02-07941

Python操作mysql数据库出现pymysql.err.ProgrammingError: (1064, "You have an error in your SQL syntax; c
今天在用Python操作mysql数据库出现pymysql.err.ProgrammingError: (1064, "You have an error in your SQL syntax; check报错"SELECT Failure_code,describe from failure_occur_now order by ID DESC LIMIT 1“黄色区域为报错的位置仔细查找,发现没有语法

0评论2023-02-07392

Oracle 笔记(2) ----PL/SQL结构、注释、变量、分支语句
1、PL/SQL块结构:DECLARE ...BEGIN......EXCEPTION........END 注意:BEGIN 和 END之间不能什么语句都没有,如果不需要语句可以写NULL2、变量命名规则:① 变量由字符开头② 可以包含字母、数字、下划线、$、# 等③ 变量长度范围:1~30④ 不区分大小

0评论2023-02-07703

mysql动态执行sql批量删除数据 sqlserver批量删除数据
 CREATE PROCEDURE `sp_delete_pushmsg_data`() BEGINdeclare l_delete_date varchar(16);declare l_state_datevarchar(16);declare l_dutynoint;declare l_row_cnt int DEFAULT 0;declare rnint default 0;declare i int default 0;set l_dutyno=101;set l_

0评论2023-02-07801

[DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase]
2016-03-24 16:39:35.687http-8080-1[INFO ][org.springframework.jdbc.support.SQLErrorCodesFactory] SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase]2016-03-24 16:39:35.687http-8080-1[DEBUG][org.

0评论2023-02-07529

配置ogg异构oracle-mysql(3)目的端配置 oracle ogg mysql
目的端配置大致分为如下三个步骤:配置mgr,配置checkpoint table,配置应用进程在目的端先创建一张表,记得带主键:mysql create database hr;Query OK, 1 row affected (0.00 sec)mysql use hrDatabase changedmysql create table ah4(id int ,name varchar

0评论2023-02-07963

MySQL客户端工具的使用与MySQL SQL语句
MySQL客户端工具的使用1、MySQL程序的组成客户端mysql:CLI交互式客户端程序mycli:CLI交互式客户端程序;使用sql语句时会有提示信息mysql_secure_installation:安全初始化,强烈建议安装完以后执行此命令mysqldump:mysql备份工具mysqladmin:官方提供的shell

0评论2023-02-07799

MySQL 5.7之关于SQL_MODE的设置
目录一、sql_mode用来解决下面几类问题二、MySQL5.7中sql_mode参数默认值的说明(如下为MySQL 5.7.27版本)三、sql_mode 设置和修改总结sql_mode是个容易被忽视的变量,在5.5默认值是空值,在这种设置下是可以允许一些非法操作的,比如允许一些非法数据的插入

0评论2023-02-07623

IIS7配置PHP5.5 对找不到的文件启用文件监视的解决方法 原创
本文主要介绍IIS7配置PHP5.5 对找不到的文件启用文件监视的解决方法,比较实用,希望能给大家做一个参考。

0评论2016-06-26728

更多推荐