🏆 作者简介,愚公搬代码
🏆《头衔》:华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,优快云博客专家,阿里云专家博主,腾讯云优秀博主,掘金优秀博主,51CTO博客专家等。
🏆《近期荣誉》:2022年优快云博客之星TOP2,2022年华为云十佳博主等。
🏆《博客内容》:.NET、Java、Python、Go、Node、前端、IOS、Android、鸿蒙、Linux、物联网、网络安全、大数据、人工智能、U3D游戏、小程序等相关领域知识。
🏆🎉欢迎 👍点赞✍评论⭐收藏
文章目录
🚀前言
数据库负载均衡指的是将数据库的请求分配到多个数据库服务器上,并通过一系列算法和策略来确保各个服务器的负载相对平衡。这样可以有效避免单个数据库服务器的过载,提高数据库的整体稳定性和性能。负载均衡器通常会监控服务器的负载情况以及数据库响应时间,根据不同的负载情况来动态调整请求的分配策略。常见的负载均衡算法包括轮询、随机、最少连接等。
本文主要介绍DeveloperSharp的使用,DeveloperSharp是一个研发中大型项目必备的系统平台,也是一个低代码平台。
它主要包括了如下一些功能:
- 基于Sql语句、存储过程、事务、分页的数据库操作。并几乎支持市面上所有种类的数据库。
- 图片操作。裁剪、缩放、加水印。
- http请求调用(Post与Get)
- 高效分页
- Web服务/WebApi的负载均衡
- 数据库的负载均衡,以及读写分离
- CORS跨域访问
- UUID全球通用唯一识别码
- MQ消息队列(请另行使用DeveloperSharp.RabbitMQ包)
- Redis缓存(请另行使用DeveloperSharp.Redis包)
- “异种数据库”的负载均衡
- 其他相关功能
🚀一、同种数据库负载均衡
🔎1.前提准备
先创建三个数据库,它们的名字分别为YG1、YG2、YG3,表结构如下
CREATE TABLE students (
id INT IDENTITY(1,1) PRIMARY KEY,
name VARCHAR(255) NOT NULL,
age INT NOT NULL,
gender VARCHAR(8) NOT NULL,
major VARCHAR(255) NOT NULL,
address VARCHAR(255) NOT NULL
);
该表包含以下字段:
- id:主键,自增长的学生ID。
- name:学生姓名,记录学生的姓名。
- age:学生年龄,记录学生的年龄。
- gender:学生性别,记录学生的性别。
- major:学生专业,记录学生的所学专业。
- address:学生地址,记录学生的地址。
对三张表分别插入数据
//----------------YG1
insert into dbo.students (name, age, gender, major, address)
values ('愚公1-1',30,'男','软件工程','福建省');
insert into dbo.students (name, age, gender, major, address)
values ('愚公2-1',30,'男','软件工程','福建省');
insert into dbo.students (name, age, gender, major, address)
values ('愚公3-1',30,'男','软件工程','福建省');
//----------------YG2
insert into dbo.students (name, age, gender, major, address)
values ('愚公1-2',30,'男','软件工程','福建省');
insert into dbo.students (name, age, gender, major, address)
values ('愚公2-2',30,'男','软件工程','福建省');
insert into dbo.students (name, age, gender, major, address)
values ('愚公3-2',30,'男','软件工程','福建省');
//----------------YG3
insert into dbo.students (name, age, gender, major, address)
values ('愚公1-3',30,'男','软件工程','福建省');
insert into dbo.students (name, age, gender, major, address)
values ('愚公2-3',30,'男','软件工程','福建省');
insert into dbo.students (name, age, gender, major, address)
values ('愚公3-3',30,'男','软件工程','福建省');
在.Net Core环境下,我们需要创建一个名为DeveloperSharp.json的配置文件,并在其中设置如上三个数据源的负载均衡策略。文件内容如下:
{
"DeveloperSharp": {
"DatabaseClusterList": [
{
"Id": "StudentData",
"DatabaseCluster": [
{
"Id": "A1",
"Enable": "true",
"Weight": "100",
"DatabaseType": "SqlServer",
"ConnectionString": "Server=localhost;Database=YG1;Uid=sa;Pwd=1"
},
{
"Id": "A2",
"Enable": "true",
"Weight": "100",
"DatabaseType": "SqlServer",
"ConnectionString": "Server=localhost;Database=YG2;Uid=sa;Pwd=1"
},
{
"Id": "A3",
"Enable": "true",
"Weight": "100",
"DatabaseType": "SqlServer",
"ConnectionString": "Server=localhost;Database=YG3;Uid=sa;Pwd=1"
}
]
}
]
}
}
对此配置文件说明如下:
-
每一个DatabaseCluster节点代表了一组数据库,此节点的Id值(本文示例值是:StudentData)后续会在程序中使用。
-
Database节点中的Weight属性代表了使用权重。本文示例的三个数据库的Weight值分别是100、100、100,则这三个数据库的负载均衡使用分配比例将会是1:1:1。若把这三个值分别设置为100、50、50,则这三个数据库的使用分配比例将会变为2:1:1。设置成你想要的比例吧。
-
Database节点中的Enable属性代表了是否可用。true代表可用,false代表不可用。
-
.Net6中可通过把DatabaseType属性的值设置为“MySql”、“SQLite”、“PostgreSql”、“Oracle”、其它等等,从而支持各种类数据库。
🔎2.安装包
DeveloperSharp
EntityFramework
🔎3.数据库负载均衡的核心器件
//这个属性就是用作映射负载均衡。
//其“值”需设置为前述DeveloperSharp.json/xml配置文件中某个DatabaseCluster节点的Id值。
[DeveloperSharp.Structure.Model.LoadBalance.DataSourceCluster("StudentData")]
public class StudentLB : DeveloperSharp.Structure.Model.DataLayer
{
//类中没有任何代码
}
说明:“负载均衡器”类(本篇为:StudentLB类)必须继承自DeveloperSharp.Structure.Model.DataLayer类,并且在其上设置DeveloperSharp.Structure.Model.LoadBalance.DataSourceCluster属性的初始化值为DeveloperSharp.json/xml配置文件中某个DatabaseCluster节点的Id值。
🔎4.相关实体类
1、Entities类
public partial class Entities : DbContext
{
public Entities()
: base("name=Entities")
{
}
public Entities(string ConnectionString)
: base(ConnectionString)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//throw new UnintentionalCodeFirstException();
}
public virtual DbSet<students> t_Student { get; set; }
}
2、students类
public class students
{
public int id { get; set; }
public string name { get; set; }
public int age { get; set; }
public string gender { get; set; }
public string major { get; set; }
public string address { get; set; }
}
🔎5.测试
using ConsoleTest;
string NameList = "";
//第一次访问数据库
var SLB = (new StudentLB()) as DeveloperSharp.Structure.Model.DataLayer;
var db = new Entities(SLB.IDA.ConnectionString);//每次会根据配置的负载均衡策略输出对应的ConnectionString
students Stu = db.t_Student.Where(t => t.id == 3).FirstOrDefault();
NameList += Stu.name;
//第二次访问数据库
SLB = (new StudentLB()) as DeveloperSharp.Structure.Model.DataLayer;
db = new Entities(SLB.IDA.ConnectionString);//每次会根据配置的负载均衡策略输出对应的ConnectionString
Stu = db.t_Student.Where(t => t.id == 3).FirstOrDefault();
NameList += Stu.name;
//第三次访问数据库
SLB = (new StudentLB()) as DeveloperSharp.Structure.Model.DataLayer;
db = new Entities(SLB.IDA.ConnectionString);//每次会根据配置的负载均衡策略输出对应的ConnectionString
Stu = db.t_Student.Where(t => t.id == 3).FirstOrDefault();
NameList += Stu.name;
//输出
Console.WriteLine(NameList);
Console.ReadLine();
🚀二、异种数据库负载均衡
🔎1.前提准备
对比同种数据库,只需要修改配置文件DeveloperSharp.json,并在其中设置如上三个数据源的负载均衡策略。文件内容如下:
{
"DeveloperSharp":
{
"DatabaseClusterList":
[
{
"Id":"StudentData",
"DatabaseCluster":
[
{
"Id":"A1",
"Enable":"true",
"Weight":"100",
"DatabaseType":"SqlServer",
"ConnectionString":"Server=localhost;Database=YG1;Uid=sa;Pwd=1"
},
{
"Id":"A2",
"Enable":"true",
"Weight":"100",
"DatabaseType":"MySql",
"ConnectionString":"Host=localhost;Database=YG2;User Id=root;password=1"
},
{
"Id":"A3",
"Enable":"true",
"Weight":"100",
"DatabaseType":"PostgreSql",
"ConnectionString":"Server=127.0.0.1;Database=YG3;Port=5432;User Id=postgres;Password=1;"
}
]
}
]
}
}
🔎2.测试
🦋2.1 第三方连接
重要的两个参数:
- SLB.IDA.ConnectionString //数据库链接字符串
- SLB.IDA.DatabaseType //数据库类型
无论你的数据库访问工具是Entity Framework、Dapper、SqlSugar、FreeSql、等等,只要有了如上两个参数,你就能自行实现相应的数据库操作。
这种方式通知数据库中介绍了就不做多说
🦋2.2 本工具连接
using ConsoleTest;
//第一次访问数据库
var SLB = (new StudentLB()) as DeveloperSharp.Structure.Model.DataLayer;
var IDA = SLB.IDA;
//接下来,直接通过IDA进行各类数据库操作
//查询多数据
var Students1 = IDA.SqlExecute<students>("select * from students");
foreach (students student in Students1)
{
Console.WriteLine(student.name);
}
var Students2 = IDA.SqlExecute<students>("select * from students");
foreach (students student in Students2)
{
Console.WriteLine(student.name);
}
var Students3 = IDA.SqlExecute<students>("select * from students");
foreach (students student in Students3)
{
Console.WriteLine(student.name);
}
Console.ReadLine();
☀️2.1.1 查询
下面,首先直接给出一个“查询多数据+选出单数据+参数”的使用示例,代码如下:
//查询多数据
var Students1 = IDA.SqlExecute<stu>("select * from t_Student");
//查询多数据(带参数)
var Students2 = IDA.SqlExecute<stu>("select * from t_Student where Id>@IdMin and Name like @LikeName", new { IdMin = 2, LikeName = "%周%" });
//另一种写法1
var IdMin = IDA.CreateParameterInput("IdMin", DbType.Int32, 2);
var LikeName = IDA.CreateParameterInput("LikeName", DbType.String, 50, "%周%");
var Students3 = IDA.SqlExecute<stu>("select * from t_Student where Id>@IdMin and Name like @LikeName", LikeName, IdMin);
//另一种写法2
var Students4 = IDA.SqlExecute<stu>("select * from t_Student").Where(t => t.Id > 2 && t.Name.Contains("周"));
//选出单数据
var OneStudent = Students2.FirstOrDefault();
其中stu实体类代码如下形式:
//此实体类中的Id、Name、Age、Birth、MyLevel属性名,要与数据表中的字段名一一对应
public class stu
{
public int? Id { get; set; }//数据库中该字段若存在Null值,类型后需要加问号?
public string Name { get; set; }
public int? Age { get; set; }
public DateTime? Birth { get; set; }
public Level? MyLevel { get; set; }//也可以使用枚举,会自动转换
}
public enum Level
{
Student=100,//学生
Teacher=200,//老师
Manager=300,//管理员
Principle=400//校长
}
☀️2.1.2 分页
若我们要对Students1、Students2进行分页操作(比如:每页20条,取出第5页),相关代码如下:
using DeveloperSharp.Extension;//调用“分页功能”需要引用此命名空间
--------------------------
var Page1 = Students1.PagePartition(20, 5);
var Page2 = Students2.PagePartition(20, 5);
//一气呵成的写法
var Page3 = IDA.SqlExecute<stu>("select * from t_Student").PagePartition(20, 5);
☀️2.1.3 增/删/改
下面是一个“修改数据+参数+事务”的使用示例:
try
{
//开启事务
IDA.TransactionBegin();
//修改数据(多语句)
int affectedRows1 = IDA.SqlExecute("insert into t_Student(Name,Age)values('ww','96');update t_Student set Age=100 where Id=1006");
//修改数据(带参数)
int affectedRows2 = IDA.SqlExecute("insert into t_Student(Name,Age)values(@N,@A)", new { N = "孙悟空", A = 200 });
//另一种写法
var NewAge = IDA.CreateParameterInput("NewAge", DbType.Int32, 200);
var NewName = IDA.CreateParameterInput("NewName", DbType.String, 50, "孙悟空");
int affectedRows3 = IDA.SqlExecute("insert into t_Student(Name,Age)values(@NewName,@NewAge)", NewName, NewAge);
//完成事务
IDA.TransactionCommit();
}
catch
{
//回滚事务
IDA.TransactionRollBack();
}
☀️2.1.4 输出参数
示例代码如下:
var op1 = IDA.CreateParameterOutput("TotalCount", DbType.Int32);//此项为输出参数
var op2 = IDA.CreateParameterOutput("MyName", DbType.String, 50);//此项为输出参数
//以下sql语句混杂了多个“输入”与“输出”参数,注意看
IDA.SqlExecute("insert into Friend(Birth,Name,height)values(@B,@N,@h);" +
"select @TotalCount=count(*) from Friend;" +
"select @MyName=Name from Friend where Id=@Id",
new { N = "杨小伟", B = "1999-02-28 12:03:45", h = 11.023, Id = 2 },
op1, op2);
int tc = Convert.ToInt32(op1.Value);
string mn = op2.Value.ToString();
☀️2.1.5 存储过程
我们创建一个存储过程,它带有输入、输出、返回三种类型的参数,代码如下:
CREATE PROCEDURE Test5
@B as datetime,
@N as nvarchar(50),
@h as float,
@TotalCount as int output,
@MyName as nvarchar(50) output,
@Id as int
AS
BEGIN
insert into Friend(Birth,Name,height)values(@B,@N,@h);
select @TotalCount=count(*) from Friend;
select @MyName=Name from Friend where Id=@Id;
return @TotalCount+100;
END
调用该存储过程的示例代码如下:
var op1 = IDA.CreateParameterOutput("TotalCount", DbType.Int32);//输出参数
var op2 = IDA.CreateParameterOutput("MyName", DbType.String, 50);//输出参数
var op3 = IDA.CreateParameterReturn();//返回参数
IDA.SpExecute("Test5", new { N = "杨小伟", B = "1999-02-28 12:03:45", h = 11.023, Id = 2 }, op1, op2, op3);
int tc = Convert.ToInt32(op1.Value);
string mn = op2.Value.ToString();
int ret = Convert.ToInt32(op3.Value);
🚀备注
IDA内功能方法详细说明(辅助参考):
SqlExecute<T> (异步为:SqlExecuteAsync<T>)
声明:IEnumerable<T> SqlExecute<T>(string cmdText, params IDataParameter[] Params) where T : class, new()
用途:执行Sql语句(Select类)
参数:(1)string cmdText -- Sql语句
(2)params IDataParameter[] Params -- 参数组
返回:IEnumerable<T> -- 多数据结果集
SqlExecute<T> (异步为:SqlExecuteAsync<T>)
声明:IEnumerable<T> SqlExecute<T>(string cmdText, object InputParams, params IDataParameter[] Params) where T : class, new()
用途:执行Sql语句(Select类)
参数:(1)string cmdText -- Sql语句
(2)object InputParams -- 输入参数对象
(3)params IDataParameter[] Params -- 参数组
返回:IEnumerable<T> -- 多数据结果集
SqlExecute (异步为:SqlExecuteAsync)
声明:int SqlExecute(string cmdText, params IDataParameter[] Params)
用途:执行Sql语句(Insert/Update/Delete类)
参数:(1)string cmdText -- Sql语句
(2)params IDataParameter[] Params -- 参数组
返回:int -- 受影响的行数
SqlExecute (异步为:SqlExecuteAsync)
声明:int SqlExecute(string cmdText, object InputParams, params IDataParameter[] Params)
用途:执行Sql语句(Insert/Update/Delete类)
参数:(1)string cmdText -- Sql语句
(2)object InputParams -- 输入参数对象
(3)params IDataParameter[] Params -- 参数组
返回:int -- 受影响的行数
SpExecute<T> (异步为:SpExecuteAsync<T>)
声明:IEnumerable<T> SpExecute<T>(string cmdText, params IDataParameter[] Params) where T : class, new()
用途:执行Sp存储过程(Select类)
参数:(1)string cmdText -- Sp存储过程名
(2)params IDataParameter[] Params -- 参数组
返回:IEnumerable<T> -- 多数据结果集
SpExecute<T> (异步为:SpExecuteAsync<T>)
声明:IEnumerable<T> SpExecute<T>(string cmdText, object InputParams, params IDataParameter[] Params) where T : class, new()
用途:执行Sp存储过程(Select类)
参数:(1)string cmdText -- Sp存储过程名
(2)object InputParams -- 输入参数对象
(3)params IDataParameter[] Params -- 参数组
返回:IEnumerable<T> -- 多数据结果集
SpExecute (异步为:SpExecuteAsync)
声明:int SpExecute(string cmdText, params IDataParameter[] Params)
用途:执行Sp存储过程(Insert/Update/Delete类)
参数:(1)string cmdText -- Sp存储过程名
(2)params IDataParameter[] Params -- 参数组
返回:int -- 受影响的行数
SpExecute (异步为:SpExecuteAsync)
声明:int SpExecute(string cmdText, object InputParams, params IDataParameter[] Params)
用途:执行Sp存储过程(Insert/Update/Delete类)
参数:(1)string cmdText -- Sp存储过程名
(2)object InputParams -- 输入参数对象
(3)params IDataParameter[] Params -- 参数组
返回:int -- 受影响的行数
🚀感谢:给读者的一封信
亲爱的读者,
我在这篇文章中投入了大量的心血和时间,希望为您提供有价值的内容。这篇文章包含了深入的研究和个人经验,我相信这些信息对您非常有帮助。
如果您觉得这篇文章对您有所帮助,我诚恳地请求您考虑赞赏1元钱的支持。这个金额不会对您的财务状况造成负担,但它会对我继续创作高质量的内容产生积极的影响。
我之所以写这篇文章,是因为我热爱分享有用的知识和见解。您的支持将帮助我继续这个使命,也鼓励我花更多的时间和精力创作更多有价值的内容。
如果您愿意支持我的创作,请扫描下面二维码,您的支持将不胜感激。同时,如果您有任何反馈或建议,也欢迎与我分享。
再次感谢您的阅读和支持!
最诚挚的问候, “愚公搬代码”