YiShaAdmin多数据库支持:MySQL与SQL Server的适配方案
你是否在开发企业级应用时,面临过需要同时支持多种数据库的困扰?比如公司内部系统长期使用SQL Server,而新项目又要求使用MySQL。YiShaAdmin作为一款基于.NET Core MVC的权限管理系统,通过精心设计的数据库适配层,完美解决了这一痛点。本文将详细介绍YiShaAdmin如何实现MySQL与SQL Server的无缝切换,读完你将掌握多数据库支持的核心设计思想和实操方法。
一、多数据库支持的核心架构
YiShaAdmin采用接口抽象与具体实现分离的设计模式,通过定义统一的数据访问接口,为不同数据库提供专属实现。这种设计不仅保证了代码的可扩展性,还使得业务逻辑层无需关心底层数据库类型。
1.1 IDatabase接口定义
IDatabase接口定义了所有数据库操作的标准方法,包括CRUD(创建、读取、更新、删除)操作、事务管理、SQL执行等。业务逻辑层通过依赖注入该接口,实现对不同数据库的透明访问。
核心接口定义如下(完整代码见YiSha.Data/YiSha.Data/IDatabase.cs):
public interface IDatabase
{
// 事务管理
Task<IDatabase> BeginTrans();
Task<int> CommitTrans();
Task RollbackTrans();
// CRUD操作
Task<int> Insert<T>(T entity) where T : class;
Task<int> Update<T>(T entity) where T : class;
Task<int> Delete<T>(Expression<Func<T, bool>> condition) where T : class, new();
Task<T> FindEntity<T>(Expression<Func<T, bool>> condition) where T : class, new();
Task<IEnumerable<T>> FindList<T>(Expression<Func<T, bool>> condition) where T : class, new();
// SQL执行
Task<int> ExecuteBySql(string strSql, params DbParameter[] dbParameter);
Task<DataTable> FindTable(string strSql, DbParameter[] dbParameter);
}
1.2 数据库适配架构图
YiShaAdmin的数据库适配层主要由以下几个部分组成:
从架构图可以看出,业务逻辑层(F)仅依赖IDatabase接口(A),具体使用MySQL还是SQL Server,由配置文件(G)中的数据库类型设置决定。这种设计使得切换数据库时,无需修改业务代码,只需更改配置即可。
二、MySQL与SQL Server的实现差异
虽然IDatabase接口定义了统一的方法,但MySQL和SQL Server在SQL语法、分页查询、事务处理等方面存在差异。YiShaAdmin通过为每种数据库提供专属实现类,处理这些差异。
2.1 MySQL实现:MySqlDatabase
MySqlDatabase类实现了IDatabase接口,针对MySQL的特性进行了优化。例如,MySQL使用LIMIT子句进行分页,MySqlDatabase在实现分页查询时,会自动生成包含LIMIT的SQL语句。
核心实现代码片段(完整代码见YiSha.Data/YiSha.Data.EF/Database/MySqlDatabase.cs):
public async Task<(int total, DataTable)> FindTable(string strSql, DbParameter[] dbParameter, string sort, bool isAsc, int pageSize, int pageIndex)
{
using (var dbConnection = dbContext.Database.GetDbConnection())
{
DbHelper dbHelper = new DbHelper(dbContext, dbConnection);
StringBuilder sb = new StringBuilder();
// 生成MySQL分页SQL
sb.Append(DatabasePageExtension.MySqlPageSql(strSql, dbParameter, sort, isAsc, pageSize, pageIndex));
object tempTotal = await dbHelper.ExecuteScalarAsync(CommandType.Text, "SELECT COUNT(1) FROM (" + strSql + ") T", dbParameter);
int total = tempTotal.ParseToInt();
if (total > 0)
{
var reader = await dbHelper.ExecuteReadeAsync(CommandType.Text, sb.ToString(), dbParameter);
DataTable resultTable = DatabasesExtension.IDataReaderToDataTable(reader);
return (total, resultTable);
}
else
{
return (total, new DataTable());
}
}
}
2.2 SQL Server实现:SqlServerDatabase
与MySqlDatabase类似,SqlServerDatabase类针对SQL Server的特性进行了适配。例如,SQL Server使用TOP关键字和ROW_NUMBER()函数进行分页,SqlServerDatabase会生成相应的分页SQL。
核心实现代码片段(完整代码见YiSha.Data/YiSha.Data.EF/Database/SqlServerDatabase.cs):
public async Task<(int total, DataTable)> FindTable(string strSql, DbParameter[] dbParameter, string sort, bool isAsc, int pageSize, int pageIndex)
{
using (var dbConnection = dbContext.Database.GetDbConnection())
{
DbHelper dbHelper = new DbHelper(dbContext, dbConnection);
StringBuilder sb = new StringBuilder();
// 生成SQL Server分页SQL
sb.Append(DatabasePageExtension.SqlServerPageSql(strSql, dbParameter, sort, isAsc, pageSize, pageIndex));
object tempTotal = await dbHelper.ExecuteScalarAsync(CommandType.Text, "SELECT COUNT(1) FROM (" + strSql + ") T", dbParameter);
int total = tempTotal.ParseToInt();
if (total > 0)
{
var reader = await dbHelper.ExecuteReadeAsync(CommandType.Text, sb.ToString(), dbParameter);
DataTable resultTable = DatabasesExtension.IDataReaderToDataTable(reader);
return (total, resultTable);
}
else
{
return (total, new DataTable());
}
}
}
2.3 关键差异对比
| 功能 | MySQL实现 | SQL Server实现 |
|---|---|---|
| 分页查询 | 使用LIMIT offset, rowcount | 使用ROW_NUMBER() OVER (ORDER BY ...) |
| 自增主键 | 通常使用AUTO_INCREMENT | 通常使用IDENTITY(1,1) |
| 字符串连接 | 使用CONCAT()函数 | 使用+运算符或CONCAT()函数 |
| 日期函数 | DATE_FORMAT() | CONVERT()或FORMAT() |
YiShaAdmin在实现层面对这些差异进行了封装,确保业务逻辑层调用统一接口时,能得到正确的结果,无需关心底层数据库的具体实现。
三、数据库脚本与初始化
为了支持多数据库,YiShaAdmin提供了针对MySQL和SQL Server的初始化脚本,包括数据库结构创建和初始数据插入。
3.1 数据库脚本文件
项目中提供的数据库脚本文件位于Document/DatabaseScript/目录下,主要包括:
mysql.sql: MySQL数据库结构创建脚本mysql_data.sql: MySQL初始数据插入脚本sqlserver.sql: SQL Server数据库结构创建脚本sqlserver_data.sql: SQL Server初始数据插入脚本
这些脚本文件确保了在不同数据库环境下,都能快速搭建起一致的数据库结构和初始数据。
3.2 数据库表结构设计
YiShaAdmin的数据库表结构设计充分考虑了兼容性,尽量使用标准SQL类型。例如,字符串类型统一使用VARCHAR,避免使用数据库特有类型(如MySQL的TEXT或SQL Server的NVARCHAR(MAX))。
以用户表(sys_user)为例,其在MySQL和SQL Server中的定义分别如下:
MySQL (mysql.sql):
CREATE TABLE `sys_user` (
`Id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`UserName` varchar(50) NOT NULL COMMENT '用户名',
`Password` varchar(100) NOT NULL COMMENT '密码',
`RealName` varchar(50) DEFAULT NULL COMMENT '真实姓名',
`Gender` tinyint(4) DEFAULT NULL COMMENT '性别(0-未知,1-男,2-女)',
`Phone` varchar(20) DEFAULT NULL COMMENT '手机号',
`Email` varchar(100) DEFAULT NULL COMMENT '邮箱',
`CreateTime` datetime NOT NULL COMMENT '创建时间',
`UpdateTime` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
SQL Server (sqlserver.sql):
CREATE TABLE [dbo].sys_user NOT NULL,
[UserName] varchar NOT NULL,
[Password] varchar NOT NULL,
[RealName] varchar NULL,
[Gender] [tinyint] NULL,
[Phone] varchar NULL,
[Email] varchar NULL,
[CreateTime] [datetime] NOT NULL,
[UpdateTime] [datetime] NULL,
CONSTRAINT [PK_sys_user] PRIMARY KEY CLUSTERED ([Id] ASC)
) ON [PRIMARY];
GO
EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'主键' , @level0type=N'SCHEMA',@level0name=N'dbo',@level1type=N'TABLE',@level1name=N'sys_user',@level2type=N'COLUMN',@level2name=N'Id'
GO
可以看出,除了自增主键的定义方式不同(MySQL使用AUTO_INCREMENT,SQL Server使用IDENTITY(1,1)),表结构基本一致,这为多数据库支持奠定了基础。
四、配置与切换
YiShaAdmin通过配置文件实现数据库类型的切换,无需修改代码。下面介绍如何在项目中配置和切换数据库。
4.1 配置文件设置
在appsettings.json中,通过DatabaseType和ConnectionString配置数据库类型和连接字符串:
{
"ConnectionStrings": {
"MySql": "server=localhost;database=yishaadmin;uid=root;pwd=123456;port=3306;charset=utf8mb4;",
"SqlServer": "Server=localhost;Database=yishaadmin;User Id=sa;Password=123456;TrustServerCertificate=True;"
},
"DatabaseType": "MySql" // 可选值: MySql, SqlServer
}
4.2 依赖注入配置
在Startup.cs中,根据配置文件的DatabaseType,注入相应的数据库实现:
public void ConfigureServices(IServiceCollection services)
{
// 读取数据库配置
var databaseType = Configuration["DatabaseType"];
var connectionString = Configuration.GetConnectionString(databaseType);
// 根据数据库类型注入相应的IDatabase实现
if (databaseType == "MySql")
{
services.AddScoped<IDatabase>(provider => new MySqlDatabase(connectionString));
}
else if (databaseType == "SqlServer")
{
services.AddScoped<IDatabase>(provider => new SqlServerDatabase(connectionString));
}
// 其他服务配置...
}
通过这种方式,业务逻辑层在需要使用数据库操作时,只需通过构造函数注入IDatabase接口即可,无需关心具体实现:
public class UserService
{
private readonly IDatabase _database;
// 构造函数注入IDatabase
public UserService(IDatabase database)
{
_database = database;
}
// 使用IDatabase进行数据库操作
public async Task<UserEntity> GetUserById(long id)
{
return await _database.FindEntity<UserEntity>(id);
}
}
4.3 运行时切换
如果需要在运行时动态切换数据库,YiShaAdmin还支持通过代码修改配置并重新初始化数据库连接。不过,在大多数场景下,建议在应用启动时确定数据库类型。
五、实际应用场景与最佳实践
5.1 应用场景
YiShaAdmin的多数据库支持适用于以下场景:
- 企业内部系统整合:同一套系统需要部署在使用不同数据库的部门。
- 产品化软件:作为通用权限管理系统,需要适应客户现有的数据库环境。
- 开发与生产环境分离:开发环境使用MySQL(轻量、免费),生产环境使用SQL Server(企业级特性)。
5.2 最佳实践
- 使用参数化查询:避免直接拼接SQL字符串,防止SQL注入,同时提高查询性能。
- 避免使用数据库特有函数:业务逻辑中尽量使用标准SQL函数,如必须使用特有函数,通过数据库适配层封装。
- 测试覆盖:确保所有功能在两种数据库环境下都经过充分测试。
- 监控与日志:记录数据库操作日志,便于排查跨数据库兼容性问题。
5.3 项目截图展示
YiShaAdmin的管理界面简洁美观,以下是系统运行在MySQL环境下的截图:
这些界面在SQL Server环境下完全一致,体现了多数据库支持的透明性。
六、总结与展望
YiShaAdmin通过接口抽象、具体实现分离的设计模式,结合针对性的数据库适配代码,实现了对MySQL和SQL Server的完美支持。这种设计不仅保证了代码的可扩展性,还使得业务逻辑层与底层数据库解耦,大大降低了维护成本。
未来,YiShaAdmin计划进一步扩展数据库支持范围,包括PostgreSQL、Oracle等主流数据库。同时,将引入数据库连接池管理、读写分离等高级特性,提升系统在高并发场景下的性能。
如果你正在寻找一款支持多数据库的权限管理系统,或者想学习多数据库适配的设计思想,YiShaAdmin无疑是一个优秀的选择。项目代码易读易懂,文档齐全,欢迎通过以下方式获取和参与项目:
- 项目地址:通过
git clone https://gitcode.com/GitHub_Trending/yi/YiShaAdmin获取源码 - 官方文档:README.md
- 数据库脚本:Document/DatabaseScript/
希望本文对你理解多数据库支持有所帮助,欢迎在项目中实践并提出宝贵意见!
点赞+收藏+关注,获取更多YiShaAdmin使用技巧和最佳实践!下期预告:《YiShaAdmin权限管理深度解析》。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考





