Bisheng 数据库实战指南:MySQL 配置、自动初始化与数据迁移一次讲透
【免费下载链接】bishengBISHENG is an open LLM devops platform for next generation Enterprise AI applications. Powerful and comprehensive features include: GenAI workflow, RAG, Agent, Unified model management, Evaluation, SFT, Dataset Management, Enterprise-level System Management, Observability and more.项目地址: https://gitcode.com/GitHub_Trending/bi/bisheng
Bisheng(毕昇)是一个面向新一代 AI 应用的开源 LLM DevOps 平台,它的全部状态都落在 MySQL 数据库里。这篇文章带你把 Bisheng 数据库这一层看穿:从 my.cnf 的字符集与 sql_mode 参数,到首次启动时的自动初始化,再到升级时的数据迁移守则,最后用一段真实的任务状态更新代码收尾。
一、先摸清家底:Bisheng 到底存了哪些数据
在动手改配置之前,先花一分钟搞清楚表里装的是什么。Bisheng 的核心实体可以归成三组:
- User / Role:用户与角色,构成基于 RBAC 的权限控制,角色还挂菜单与资源授权;
- Flow / FlowVersion:工作流定义与其版本记录,每次发布的流程都有独立的版本快照;
- Session / Task:AI 会话与任务执行状态,一次对话跑出来的每个任务节点都会落库,方便随时恢复和追溯。
这些表的模型定义用 SQLAlchemy + SQLModel 编写,全部放在src/backend/bisheng/database/models/目录下;会话(含同步与异步两套入口)由src/backend/bisheng/database/base.py统一管理。后面所有读操作都走这套会话。
二、动手之前:给 MySQL 做一次参数体检
Bisheng 的 MySQL 参数写死在docker/mysql/conf/my.cnf里,Docker 部署时直接生效。真正起决定作用的是下面这几行:
[mysqld] init_connect='SET collation_connection = utf8mb4_unicode_ci, NAMES utf8mb4' # 服务器级字符集 character-set-server=utf8mb4 collation-server=utf8mb4_unicode_ci # 严格模式:拒绝非法值入库 sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION每个参数各管一件事:
- utf8mb4 字符集:四字节编码,emoji、生僻字、特殊符号都能原样存下来,不会变问号;
- STRICT_TRANS_TABLES 严格模式:非法的日期、超长的值直接被拒,而不是悄悄截断,数据质量从入口就守住;
- 统一 utf8mb4_unicode_ci 排序规则:连接层和服务器层同一套 collation,中文按拼音或笔画排序时不会出现"同一词排两行"的怪事。
三、第一次启动:系统自动做了哪些初始化
你第一次把 Bisheng 跑起来,并不需要手工建表灌数据。入口在src/backend/bisheng/database/init_data.py的init_default_data里,整个过程分五步:
- 防重锁:向 Redis 申请
init_default_data锁,抢不到就直接退出; - 建库建表:调用
create_db_and_tables按 ORM 模型创建库表; - 判空:先查角色表是否已有记录,有就跳过;
- 写默认角色:插入"系统管理员"和"普通用户"两个角色;
- 导入默认数据:创建默认管理员用户,并导入组件与模板数据。
下面的精简片段就是这套"幂等"逻辑的骨架:
async def init_default_data(): if await redis_client.asetNx('init_default_data', '1'): await db_service.create_db_and_tables() async with async_session_getter() as session: db_role = (await session.exec(select(Role).limit(1))).all() if not db_role: session.add(Role(id=AdminRole, role_name='系统管理员')) session.add(Role(id=DefaultRole, role_name='普通用户')) await session.commit()redis_client.asetNx用的是 Redis 的"不存在才设置"语义:多实例同时启动时,只有第一个实例能拿到锁继续初始化,其余实例直接跳过,避免重复建表或重复插角色。
四、升级不炸库:Bisheng 数据迁移的四条守则
初始化只跑一次,之后你面对的更多是升级。已有的数据要安全演进,Bisheng 实践里守着四条规矩:
- 版本化:流程数据按 FlowVersion 表留版本,每次发布都有独立结构记录,出问题可以定位到具体版本再回滚;
- 增量 ALTER:新增字段、改索引都走 ALTER TABLE 增量变更,绝不删库重建——旧数据是资产,不是包袱;
- 迁移前备份:动核心表之前先备份,备份文件不在同一个故障域里才算数;
- 事务原子性:单次迁移包在事务里执行,要么整批成功,要么整批回滚,数据库里不会出现"迁移到一半"的中间态。
五、走读一次真实读写:任务状态更新
讲完结构,看一段真实读写。灵思(Linsight)的执行任务模型定义在src/backend/bisheng/linsight/domain/models/linsight_execute_task.py,LinsightExecuteTaskDao.update_by_id是典型的异步会话套路——查询、判空、逐字段赋值、提交、回读:
async def update_by_id(cls, task_id: str, **kwargs): async with async_session_getter() as session: task = (await session.exec( select(LinsightExecuteTask).where(LinsightExecuteTask.id == task_id) )).first() if not task: return None for key, value in kwargs.items(): setattr(task, key, value) session.add(task) await session.commit() await session.refresh(task) return task这个模型有三个设计在替高并发场景兜底:主键是 UUID(CHAR(36)),并发插入不抢自增 ID 的写热点;task_type与status都是枚举字段,状态取值被限制在ExecuteTaskTypeEnum/ExecuteTaskStatusEnum定义的集合里,不会写进脏值;create_time带server_default=CURRENT_TIMESTAMP,时间戳由数据库生成,审计追踪不依赖应用层传参。
六、下一步往哪看
想再往深里走,三个目录值得挨个翻:
- database/models:完整的数据模型定义,看每张表长什么样;
- workflow:工作流引擎如何与这些表交互;
- knowledge:知识库的数据管理与检索链路。
顺着代码从表结构读到引擎,Bisheng 的数据库层就没有黑盒了。
【免费下载链接】bishengBISHENG is an open LLM devops platform for next generation Enterprise AI applications. Powerful and comprehensive features include: GenAI workflow, RAG, Agent, Unified model management, Evaluation, SFT, Dataset Management, Enterprise-level System Management, Observability and more.项目地址: https://gitcode.com/GitHub_Trending/bi/bisheng
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考