1. 概述
本系统采用了基于 SQLAlchemy 2.0 的异步数据库架构,实现了自动化的数据库表创建和基础数据初始化。整个初始化过程由 InitializeData 类(位于 app/scripts/initialize.py)统一管理,遵循"先创建表结构,再初始化数据"的原则,确保数据完整性和依赖关系正确性。
2. 数据库连接配置
2.1 连接管理
系统使用 app/core/database.py 中的函数创建数据库连接:
create_engine_and_session(): 创建同步数据库引擎和会话工厂create_async_engine_and_session(): 创建异步数据库引擎和会话工厂
这些函数从配置文件中读取数据库连接参数,支持多种数据库类型(SQLite、MySQL、PostgreSQL)。
2.2 核心配置参数
- 数据库连接URL:
settings.DB_URI(同步)和settings.ASYNC_DB_URI(异步) - 连接池配置: 包括连接池大小、回收时间、预检查等
- 日志配置: 控制是否输出SQL语句
3. 模型定义架构
3.1 基础模型设计
系统采用了Mixin模式实现模型的复用和扩展:
python
class MappedBase(AsyncAttrs, DeclarativeBase):
__abstract__: bool = True
class ModelMixin(MappedBase):
__abstract__: bool = True
# 提供通用字段:id、uuid、status、description、created_time、updated_time
class UserMixin(MappedBase):
__abstract__: bool = True
# 提供用户审计字段:created_id、updated_id
3.2 业务模型定义
业务模型通过继承基础模型实现,例如用户模型:
python
class UserModel(ModelMixin, UserMixin):
__tablename__: str = "sys_user"
__table_args__: dict[str, str] = ({'comment': '用户表'})
username: Mapped[str] = mapped_column(String(32), nullable=False, unique=True, comment="用户名/登录账号")
password: Mapped[str] = mapped_column(String(255), nullable=False, comment="密码哈希")
# 其他字段...
# 关联关系
dept: Mapped["DeptModel | None"] = relationship(back_populates="users", lazy="selectin")
roles: Mapped[list["RoleModel"]] = relationship(secondary="sys_user_roles", back_populates="users", lazy="selectin")
4. 表创建过程
4.1 模型加载与依赖排序
在 InitializeData 类中,模型按照依赖关系排序:
python
self.prepare_init_models = [
MenuModel,
ParamsModel,
DeptModel,
RoleModel,
DictTypeModel,
DictDataModel,
PositionModel,
UserModel,
UserRolesModel,
]
4.2 表创建实现
表创建通过 SQLAlchemy 的 metadata.create_all() 方法实现:
python
async def __init_create_table(self) -> None:
try:
async with async_engine.begin() as conn:
await conn.run_sync(MappedBase.metadata.create_all)
log.info("✅️ 数据库表结构初始化完成")
except Exception as e:
log.error(f"❌️ 数据库表结构初始化失败: {str(e)}")
raise
这个方法会自动创建所有继承自 MappedBase 的模型对应的数据库表,并处理表之间的外键关系。
5. 数据初始化过程
5.1 初始化数据存储
基础数据存储在 app/scripts/data/ 目录下的 JSON 文件中,每个文件对应一个表:
kotlin
data/
├── sys_dept.json
├── sys_dict_data.json
├── sys_dict_type.json
├── sys_menu.json
├── sys_param.json
├── sys_role.json
├── sys_user.json
└── sys_user_roles.json
5.2 数据加载与插入
数据初始化过程包括以下步骤:
- 检查表是否已有数据:避免重复初始化
- 读取初始化数据文件:从 JSON 文件中加载数据
- 特殊数据处理 :
- 嵌套数据处理(如部门和菜单的树形结构)
- 关联数据处理(如字典数据与字典类型的关联)
- 批量插入数据 :使用
db.add_all()和db.flush()批量插入
5.3 特殊数据处理实现
5.3.1 嵌套数据处理
对于具有树形结构的数据(如部门和菜单),系统使用递归函数创建对象:
python
def __create_objects_with_children(self, data: list[dict], model_class) -> list:
objs = []
def create_object(obj_data: dict):
children_data = obj_data.pop('children', [])
obj = model_class(**obj_data)
if children_data:
obj.children = [create_object(child) for child in children_data]
return obj
for item in data:
objs.append(create_object(item))
return objs
5.3.2 关联数据处理
对于存在关联关系的数据(如用户与角色),系统先初始化主表数据,再初始化关联表数据:
python
# 处理字典类型表,保存类型映射
elif table_name == "sys_dict_type":
objs = []
for item in data:
obj = model(**item)
objs.append(obj)
dict_type_mapping[item['dict_type']] = obj
# 处理字典数据表,添加dict_type_id关联
elif table_name == "sys_dict_data":
objs = []
for item in data:
dict_type = item.get('dict_type')
if dict_type in dict_type_mapping:
item['dict_type_id'] = dict_type_mapping[dict_type].id
else:
log.warning(f"⚠️ 未找到字典类型 {dict_type},跳过该字典数据")
continue
objs.append(model(**item))
6. 完整初始化流程
数据库初始化的完整流程由 init_db() 方法统一协调:
python
async def init_db(self) -> None:
# 先创建表结构
await self.__init_create_table()
# 再初始化数据
async with async_db_session() as session:
async with session.begin():
await self.__init_data(session)
await session.commit()
8. 总结
本系统的数据库初始化过程是一个高度自动化、可扩展的架构,通过 SQLAlchemy 2.0 的异步特性实现了高效的数据库操作。整个过程遵循了"先创建表结构,再初始化数据"的原则,确保了数据的完整性和依赖关系的正确性。同时,系统采用了Mixin模式实现模型的复用和扩展,提高了代码的可维护性。