我给自己的 Go 后台接入了 SQL Server,顺便聊聊 ShiyuAdmin 的架构设计

简介: JavaPub开源的Go+React后台脚手架ShiyuAdmin,新增SQL Server支持,通过GORM多方言抽象实现PostgreSQL/MySQL/SQLite/SQL Server四库统一适配,业务层零修改。架构清晰分层(API→Service→Repository),RBAC权限完备,含用户、菜单、日志等通用模块,并提供各数据库Docker Compose部署方案。(239字)

大家好,我是 JavaPub。

最近又重新折腾了一下我自己的开源后台项目 ShiyuAdmin

项目地址:

https://github.com/Rodert/ShiyuAdmin

这次主要做的一件事情,是给项目补上了 SQL Server 支持

在这里插入图片描述

如果只是站在“能不能连接 SQL Server”的角度来看,这件事情其实非常简单。

Go 里面加一个驱动:

gorm.io/driver/sqlserver

然后:

gorm.Open(sqlserver.Open(dsn))

理论上数据库就连上了。

但对于一个已经存在用户、角色、菜单、权限、日志、数据管理、系统监控等模块的后台脚手架来说,真正的问题并不是:

怎么连接 SQL Server?

而是:

怎么在不改业务代码的情况下,让同一套后台同时跑在 PostgreSQL、MySQL、SQLite 和 SQL Server 上?

这就是这次改造比较有意思的地方。

今天就借这个机会,聊聊现在 ShiyuAdmin 的整体架构,以及 SQL Server 是怎么接进去的。


一、先看一下 ShiyuAdmin 是什么

ShiyuAdmin 本身定位并不是一个具体业务系统。

它更像是一套:

Go + React 的通用后台管理脚手架。

目前后端主要使用:

Go
Gin
Gorm
Viper
JWT
Redis

前端则是:

React
TypeScript
Umi Max
Ant Design Pro
ECharts

项目采用标准的前后端分离模式。后端负责 API、权限、数据库和业务逻辑,前端负责管理后台 UI。

项目现在主要包含这些基础能力:

用户管理
角色管理
菜单管理
部门管理
RBAC 权限
JWT 登录认证
动态菜单
超级管理员
操作日志
Redis 管理
系统监控
数据库管理
数据仪表盘

这些东西本质上都是后台系统绕不开的公共能力。

所以我做这个项目一直有一个思路:

新项目不要每次从登录、权限、用户、菜单重新写。

真正做业务的时候,在这个脚手架上继续增加自己的业务模块就可以了。


二、整体架构其实很清晰

现在 ShiyuAdmin 后端目录大概是这样的:

backend/shiyu-admin-backend
├── cmd
│   └── server
├── configs
├── internal
│   ├── api
│   ├── bootstrap
│   ├── config
│   ├── middleware
│   ├── model
│   ├── repository
│   ├── server
│   └── service
├── migrations
├── pkg
│   ├── database
│   ├── redis
│   ├── jwtutil
│   └── logger
└── sql

如果把它抽象一下,大致可以理解成:

            React / Ant Design Pro
                      │
                      │ HTTP
                      ▼
                  Gin Router
                      │
              Middleware Layer
        JWT / RBAC / Log / Trace
                      │
                      ▼
                  API Layer
                      │
                      ▼
                Service Layer
                      │
                      ▼
              Repository Layer
                      │
                      ▼
                    GORM
                      │
       ┌──────────────┼──────────────┐
       ▼              ▼              ▼
 PostgreSQL         MySQL        SQL Server
                                      │
                                   SQLite

这个结构看起来并不复杂。

但对后台脚手架来说,其实我反而比较喜欢这种架构。

因为:

后台管理系统最大的敌人不是代码少,而是业务越来越多以后所有东西搅在一起。


三、第一层:API 层只负责 HTTP

比如用户管理接口,API 层应该解决的是:

接收参数
参数校验
调用 Service
返回 JSON
HTTP 状态处理

而不应该在 API Handler 里面直接写:

db.Where(...)
db.Create(...)
db.Delete(...)

否则随着业务越来越多,很快就会出现这种代码:

Handler
 ├── HTTP
 ├── SQL
 ├── 权限
 ├── 业务判断
 ├── 数据转换
 └── 日志

最后一个接口可能几百行。

所以 ShiyuAdmin 里面真正的业务逻辑主要继续往下走:

API
 ↓
Service
 ↓
Repository

四、Service 才是业务核心

Service 层做什么?

举个用户管理的例子。

比如:

创建用户

它并不仅仅对应:

INSERT INTO sys_users

还可能涉及:

检查用户名
检查用户编码
密码 BCrypt 加密
部门是否合法
分配角色
数据权限
记录日志

所以这些东西应该属于 Service。

Service 不应该过于关心:

底层到底是 PostgreSQL
还是 MySQL
还是 SQL Server

这也是这次接 SQL Server 能比较顺利的关键原因之一。


五、Repository 才真正负责数据库

再向下一层就是 Repository。

现在 Server 初始化的时候,会统一创建各种 Repository:

authRepo = repoDB.NewAuthRepository(db)
userRepo = repoDB.NewUserRepository(db)
roleRepo = repoDB.NewRoleRepository(db)
menuRepo = repoDB.NewMenuRepository(db)
deptRepo = repoDB.NewDeptRepository(db)

userRoleRepo = repoDB.NewUserRoleRepository(db)
roleMenuRepo = repoDB.NewRoleMenuRepository(db)
roleDeptRepo = repoDB.NewRoleDeptRepository(db)

operationLogRepo = repoDB.NewOperationLogRepository(db)
dbMetaRepo = repoDB.NewDBMetaRepository(db)

然后再注入对应的 Service。

于是就形成了:

User API
   ↓
User Service
   ↓
User Repository
   ↓
GORM

这时候有一个非常重要的好处出现了。

上面的:

API
Service
Repository

基本不用知道底下是什么数据库。

这就是多数据库架构最关键的一点。


六、SQL Server 到底是怎么接进来的?

这次 SQL Server 接入最核心的位置,其实在:

pkg/database/database.go

数据库统一从:

database.Connect(cfg)

进去。

然后根据:

cfg.Database.Driver

决定加载哪个 GORM Dialector。

现在结构大概就是:

switch cfg.Database.Driver {
   

case "postgres", "postgresql":
    dialector = postgres.Open(dsn)

case "mysql":
    dialector = mysql.Open(dsn)

case "sqlite":
    dialector = sqlite.Open(...)

case "sqlserver", "mssql":
    dialector = sqlserver.Open(dsn)

default:
    return nil, errors.Errorf(
        "unsupported database driver: %s",
        cfg.Database.Driver,
    )
}

也就是说:

SQL Server 并没有入侵业务层。

它只是在数据库基础设施层新增了一个 Dialector。

于是上层仍然拿到同样的:

*gorm.DB

后面:

Repository
Service
API

基本不需要发生变化。

我认为这才是一套通用后台应该有的数据库接入方式。


七、为什么我没有到处判断数据库类型

一种比较容易出现的写法是:

if driver == "mysql" {
   

}

if driver == "postgres" {
   

}

if driver == "sqlserver" {
   

}

然后慢慢演变成:

if sqlserver {
   
    ...
} else if mysql {
   
    ...
} else {
   
    ...
}

如果这些判断出现在 Repository、Service 甚至 API 层,整个项目很快就废了。

因为增加一个数据库意味着:

改连接层
改 Repository
改 Service
改 Handler
改初始化

而现在 ShiyuAdmin 的原则更接近:

                    database.Connect
                           │
             ┌─────────────┼─────────────┐
             │             │             │
        PostgreSQL       MySQL       SQL Server
             │             │             │
             └─────────────┼─────────────┘
                           │
                        *gorm.DB
                           │
                    Repository
                           │
                      Service
                           │
                         API

数据库差异尽量截止在:

Database / Repository

这一层。


八、SQL Server 的 DSN 也单独处理了

PostgreSQL 的连接方式一般类似:

host=
user=
password=
dbname=
port=
sslmode=

MySQL 又是另外一套:

user:password@tcp(host:port)/database

SQL Server 则使用:

sqlserver://username:password@host:1433

所以项目里没有强行让所有数据库拼同一种 DSN。

SQL Server 使用 URL 形式构造:

dsnURL := &url.URL{
   
    Scheme: "sqlserver",
    User: url.UserPassword(
        cfg.Database.Username,
        cfg.Database.Password,
    ),
    Host: net.JoinHostPort(
        cfg.Database.Host,
        fmt.Sprintf("%d", cfg.Database.Port),
    ),
}

然后增加:

query.Set("database", cfg.Database.Database)

以及加密配置:

query.Set("encrypt", cfg.Database.SSLMode)

最后:

sqlserver.Open(dsnURL.String())

这样做还有个好处。

账号密码如果带一些特殊字符,不需要自己疯狂处理:

@
:
/
#
?

URL 编码可以减少很多 DSN 拼接问题。


九、数据库连接池还是统一管理

不管使用哪一种数据库,最终都会得到:

sqlDB, err := db.DB()

然后统一设置连接池:

sqlDB.SetMaxOpenConns(50)
sqlDB.SetMaxIdleConns(10)
sqlDB.SetConnMaxLifetime(30 * time.Minute)

所以现在:

PostgreSQL
MySQL
SQL Server
SQLite

在应用层看到的都是:

GORM
  ↓
database/sql
  ↓
数据库驱动

这也意味着后续如果需要做:

连接池配置化
连接超时
慢 SQL
Metrics
数据库健康检查

都可以继续统一放到 Database 层,而不是污染业务代码。


十、配置层也完全独立

SQL Server 已经有单独的配置:

configs/config.sqlserver.yaml

例如:

database:
  driver: "sqlserver"
  host: "shiyu-sqlserver"
  port: 1433
  username: "sa"
  password: "******"
  database: "shiyu_admin_scaffold"
  ssl_mode: "disable"

也就是说切换数据库本质变成:

换配置
而不是改业务代码

这点非常重要。

理想情况下,你甚至可以:

CONFIG_FILE=configs/config.sqlserver.yaml

启动 SQL Server 环境。

换一个配置:

CONFIG_FILE=configs/config.mysql.yaml

就是 MySQL。

整个应用架构不变。


十一、Docker Compose 也拆成了四套数据库模式

目前项目已经不只是代码层支持多数据库,部署层也开始分离。

现在分别提供:

docker-compose.yml
docker-compose.mysql.yml
docker-compose.sqlserver.yml
docker-compose.sqlite.yml

对应:

数据库 使用场景
PostgreSQL 默认生产环境
MySQL 8.4 已有 MySQL 基础设施
SQL Server 2022 企业 SQL Server 环境
SQLite 本地、演示、轻量部署

SQL Server 可以直接:

docker compose -f docker-compose.sqlserver.yml up -d

启动。

这一点我觉得比“代码里支持 SQL Server”更重要。

因为一个开源脚手架真正要降低的是:

从 Git Clone 到系统跑起来之间的成本。


十二、为什么我要支持 SQL Server?

很多做互联网项目的同学可能会问:

都 2026 年了,为什么还专门接 SQL Server?

原因其实很现实。

如果只看互联网创业项目:

MySQL
PostgreSQL

确实已经占据了绝大多数场景。

但是到了:

传统企业
制造业
ERP
医院
学校
政府项目
.NET 老系统
内部管理系统

SQL Server 依然非常常见。

尤其很多企业已经存在大量:

SQL Server
Windows Server
.NET
ERP
OA
MES

基础设施。

你不可能跟甲方说:

为了用我的后台框架,请你们先把数据库换成 PostgreSQL。

这显然不现实。

所以对于一套“通用后台脚手架”来说,多数据库支持其实不是炫技。

而是在解决一个非常现实的问题:

降低接入现有企业基础设施的成本。


十三、GORM 在这里的价值就体现出来了

很多人会讨论:

到底要不要 ORM?

如果是一个非常极致的高性能服务,我可能会倾向于:

sqlc
原生 SQL
手写 DAO

但 ShiyuAdmin 的定位不一样。

它是:

通用中后台脚手架。

这里更重要的目标是:

快速开发
CRUD 效率
代码一致性
多数据库适配
维护成本

GORM 在这个场景里其实非常合适。

比如启动的时候项目统一执行:

db.AutoMigrate(
    &entity.User{
   },
    &entity.Role{
   },
    &entity.Menu{
   },
    &entity.Dept{
   },
    &entity.UserRole{
   },
    &entity.RoleMenu{
   },
    &entity.RoleDept{
   },
    &entity.OperationLog{
   },
    ...
)

核心 RBAC 表可以直接根据 Entity 初始化。

所以:

同一套 Entity
      ↓
     GORM
      ↓
PostgreSQL / MySQL / SQL Server / SQLite

这让多数据库维护成本低了非常多。


十四、RBAC 其实也是整个项目最核心的一层

数据库之外,我觉得 ShiyuAdmin 另一个比较核心的设计就是 RBAC。

目前整体关系可以理解成:

User
  │
  ▼
UserRole
  │
  ▼
Role
  │
  ├────────► RoleMenu ────────► Menu
  │
  └────────► RoleDept ────────► Dept

也就是:

用户
 ↓
角色
 ↓
菜单 / 权限

同时角色还可以继续关联:

部门
数据范围

这也是为什么系统不仅可以做到:

这个用户能不能看到菜单

还可以继续向:

这个用户能不能调用 API
这个角色可以看哪些部门
这个角色可以操作哪些数据

扩展。

项目的 JWT 中还单独加入了:

IsSuperAdmin bool

超级管理员可以直接绕过普通 RBAC 权限检查。普通账号则继续根据用户、角色、菜单关系计算权限。

这个设计对于后台系统很实用。

因为一定要给运维留一条:

“最高权限救场通道”。


十五、应用启动过程其实也体现了架构

现在启动过程大概是:

main.go
   ↓
加载 Config
   ↓
server.Run()
   ↓
初始化 Logger
   ↓
初始化 Gin
   ↓
database.Connect()
   ↓
AutoMigrate()
   ↓
初始化默认管理员
   ↓
初始化 RBAC
   ↓
初始化 Redis
   ↓
创建 Repository
   ↓
创建 Service
   ↓
注册 API
   ↓
启动 HTTP Server

Server 层实际上扮演的是一个:

依赖组装器。

数据库、Repository、Service 都在这里完成组合。

所以业务代码本身不会到处:

gorm.Open(...)
redis.NewClient(...)

所有基础设施集中初始化。

这一点对于后面做:

Mock
单元测试
替换数据库
增加缓存
增加 MQ

都会比较舒服。


十六、这次 SQL Server 改造,我最满意的并不是“支持 SQL Server”

如果只是:

✔ SQL Server

其实没有什么技术含量。

真正让我觉得这次改造有价值的是:

SQL Server 加进来以后,原来的 API、Service、RBAC 和大部分 Repository 并没有因此被破坏。

换句话说:

增加一个基础设施

没有演变成:

重写一遍业务系统。

这其实就是架构设计真正有价值的地方。

好的架构不是:

看起来用了多少设计模式。

而是:

当需求发生变化的时候,需要改多少地方。


十七、现在这套架构可以继续怎么演进?

接下来其实还有几个方向可以继续完善。

1. 数据库能力矩阵

不同数据库并不是百分百一样。

以后可以做一份明确的:

PostgreSQL   ✅
MySQL        ✅
SQL Server   ✅
SQLite       ✅

然后针对:

表注释
字段类型
分页
JSON
全文索引
事务
DDL
元数据查询

分别测试兼容性。


2. 数据库差异继续下沉

未来如果出现:

SQL Server 特有 SQL
PostgreSQL 特有 SQL
MySQL 特有 SQL

不要让它进入 Service。

而应该继续下沉到:

Repository
DBMetaRepository
Dialect Adapter

例如:

DBMetaRepository
       │
       ├── PostgreSQL Metadata
       ├── MySQL Metadata
       └── SQL Server Metadata

这样数据管理、表结构查看这些功能才能真正做到跨数据库。


3. 连接池配置化

现在连接池参数是统一配置的:

MaxOpenConns = 50
MaxIdleConns = 10
ConnMaxLifetime = 30min

未来最好进一步配置化:

database:
  max_open_conns: 50
  max_idle_conns: 10
  conn_max_lifetime: 30m

因为不同部署规模的数据库并不应该使用完全相同的参数。


4. 把多数据库加入 CI

这是我认为非常重要的一步。

以后提交代码的时候最好直接跑:

PostgreSQL Test
MySQL Test
SQL Server Test
SQLite Test

否则:

“理论兼容”

和:

“每次 Commit 都验证兼容”

完全是两回事。


十八、最后

ShiyuAdmin 从一开始我就没有想把它做成一个特别重的“大而全框架”。

我的目标一直比较简单:

把后台项目里重复率最高的那 60%~80% 基础工作提前做好。

例如:

登录
JWT
RBAC
用户
角色
菜单
部门
日志
Redis
监控
数据库
Docker
前端后台

这些东西一旦稳定下来,以后真正开发业务系统的时候,就可以直接:

写业务。

而不是每开一个新项目:

第 1 天:写登录
第 2 天:写用户
第 3 天:写角色
第 4 天:写菜单
第 5 天:写权限
……

这次加入 SQL Server,也是沿着这个方向继续走。

现在底层已经可以覆盖:

PostgreSQL
MySQL
SQL Server
SQLite

我觉得对于一套 Go 后台脚手架来说,数据库层基本已经有了一个比较完整的雏形。SQL Server 2022 也已经有独立的 Docker Compose 部署方案。

后面我还会继续完善:

多数据库兼容
数据权限
代码生成
文件管理
系统监控
部署能力
自动化测试

如果你平时也在做:

Go
Gin
GORM
React
企业后台
RBAC
SQL Server

可以看看这个项目。

services:
  shiyu-sqlserver:
    image: mcr.microsoft.com/mssql/server:2022-latest
    platform: linux/amd64
    container_name: shiyu-sqlserver
    restart: unless-stopped
    environment:
      ACCEPT_EULA: "Y"
      MSSQL_PID: "Developer"
      MSSQL_SA_PASSWORD: "ShiyuAdmin@123"
    ports:
      - "11433:1433"
    volumes:
      - shiyu-sqlserver-data:/var/opt/mssql
    healthcheck:
      test: ["CMD-SHELL", "timeout 2 bash -c '</dev/tcp/127.0.0.1/1433'"]
      interval: 10s
      timeout: 5s
      retries: 15
      start_period: 30s
    networks: [shiyu-network]

  shiyu-sqlserver-init:
    image: mcr.microsoft.com/mssql-tools18:latest
    platform: linux/amd64
    container_name: shiyu-sqlserver-init
    restart: "no"
    environment:
      MSSQL_SA_PASSWORD: "ShiyuAdmin@123"
    depends_on:
      shiyu-sqlserver:
        condition: service_healthy
    command:
      - /bin/bash
      - -c
      - >
        /opt/mssql-tools18/bin/sqlcmd -S shiyu-sqlserver -U sa -P "$$MSSQL_SA_PASSWORD" -C
        -Q "IF DB_ID(N'shiyu_admin_scaffold') IS NULL CREATE DATABASE [shiyu_admin_scaffold]"
    networks: [shiyu-network]

  shiyu-redis:
    image: redis:7
    container_name: shiyu-redis
    restart: unless-stopped
    volumes:
      - shiyu-redis-data:/data
    command: redis-server --appendonly yes
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks: [shiyu-network]

  shiyu-app:
    image: ${SHIYU_IMAGE:-ghcr.io/rodert/shiyuadmin:latest}
    container_name: shiyu-app
    restart: unless-stopped
    environment:
      TZ: Asia/Shanghai
      CONFIG_FILE: configs/config.sqlserver.yaml
    ports:
      - "18000:80"
    depends_on:
      shiyu-sqlserver-init:
        condition: service_completed_successfully
      shiyu-redis:
        condition: service_healthy
    networks: [shiyu-network]

networks:
  shiyu-network:
    driver: bridge

volumes:
  shiyu-sqlserver-data:
  shiyu-redis-data:

image.png

我是王仕宇

GitHub:

https://github.com/Rodert/ShiyuAdmin

也欢迎一起提 Issue、PR,或者把它直接拿去作为自己项目的基础骨架。

一起成为勇猛精进的人类。

目录
相关文章
|
7天前
|
存储 弹性计算 缓存
阿里云服务器租赁费用:新版租赁收费标准及活动报价参考
本文更新了2026年阿里云全系列云服务器租赁活动报价,所有特惠资源均可前往阿里云活动中心选购,整体覆盖从个人入门到企业级高性能场景的全梯度需求。其中轻量应用服务器主打极致性价比,2核2G峰值200M带宽配置每日10点、15点限时抢购价仅38元/年,2核4G配置379元/年起;高性价比的经济型e实例、通用算力型u2i实例覆盖2核4G至4核32G全档位,适配开发测试与中小型企业业务;搭载英特尔至强6处理器的第九代c9i企业级实例算力较上代提升20%,支撑高并发生产环境,不同实例规格价差清晰,用户可根据自身业务负载与预算灵活选型。
1745 117
|
8天前
|
人工智能 程序员 API
Codex 接入 DeepSeek-V4-Flash:还能补上识图,提供两套方案
Codex 接入 DeepSeek-V4-Flash 怎么配?本文覆盖 CLI 与桌面端,再用 qwen3-vl-flash 补识图,两套方案可直接照做
1250 9
|
14天前
|
云安全 人工智能 运维
阿里云联动百位企业安全专家,共识Agent防御最佳实践
当Agent成为新员工,你的安全边界在哪里?
1956 9
阿里云联动百位企业安全专家,共识Agent防御最佳实践
|
8天前
|
编解码 人工智能 安全
2核4G/4核8G/8核16G阿里云服务器如何选择实例?经济型e、通用算力型u2i与计算型c9i选哪个?
本文介绍了阿里云2核4G、4核8G、8核16G三档主流配置下经济型e、通用算力型u2i和计算型c9i三种实例的最新活动价格与适用场景。同配置下三者价差显著,以2核4G为例,经济型e低至599.93元/年,计算型c9i则高达1742.08元/年。文章详细解析了各实例的性能定位:经济型e适合轻负载入门场景,u2i兼顾稳定算力与性价比,c9i凭借第9代至强处理器与芯片级安全能力支撑高性能业务。同时提示用户可叠加满减优惠券享受折上折,建议根据业务负载与预算综合决策。
543 112
缓存 安全 IDE
958 2
|
20天前
|
人工智能 前端开发 Linux
Codex 桌面版安装 + CC Switch 接入第三方 API 完整教程(2026 最新)
2026最新教程:手把手教你安装Codex桌面版,通过CC Switch v3.17.0一键接入Fenno等国产API(兼容OpenAI Responses格式),跳过账号登录,完整启用代码审查、多步任务与上下文感知功能。零基础友好,全程图文实操。(239字)
2941 4
|
8天前
|
人工智能 JSON Shell
2026AI漫剧本地全开源方案(附各个软件模型链接),8G显卡也能流畅运行
这是一套完全本地化部署的AI漫剧生成技术链路:涵盖LLM剧本分镜生成、FLUX文生图(IP-Adapter人脸锁定)、StoryDiffusion时序连贯控制、LTX-2.3唇形同步视频生成,及ComfyUI全流程调度。零云端费用,仅耗硬件算力,单集2–4小时可产出竖屏短视频,适配抖音/B站分发。
|
5天前
|
编解码 弹性计算 云计算
MiniMax-H3 视频生成模型 — 一键部署与使用指南
MiniMax-H3是MiniMax开源的33B全模态视频生成模型,支持文生视频、图生视频、参考生视频三种模式,原生输出2K/15秒带立体声音频视频,已原生适配ComfyUI,并可通过阿里云计算巢一键部署。(239字)
|
12天前
|
存储 人工智能 关系型数据库
阿里云AI产品与云产品最新组合套餐:Token Plan、AI coding及云服务器和建站等组合优惠价
阿里云推出全新“算力+模型+应用”一站式云与AI组合套餐活动,覆盖从个人开发者到中大型企业的全场景需求。核心亮点为分三档定价的Token Plan订阅服务,支持Qwen3.8-Max-Preview大模型调用,错峰时段最低可享0.2折优惠。活动同步推出AI Coding、智能体部署、云电脑托管、0代码建站等十余类场景化组合,搭配99元/年的普惠云服务器、88元/年的入门数据库等经典特惠产品,还为企业提供1V1定制化AI转型方案,大幅降低了不同用户群体拥抱AI的技术门槛与采购成本。
748 111