You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3.1 KiB
3.1 KiB
修复文件夹迁移的 asyncpg 兼容性问题
日期:2026-01-29
类型:Bug 修复
影响范围:数据库迁移
问题描述
在执行 20260129_1410_create_folder_shares_and_export_jobs.py 迁移时,遇到以下错误:
asyncpg.exceptions.PostgresSyntaxError: cannot insert multiple commands into a prepared statement
原因:asyncpg 驱动不支持在一个 prepared statement 中执行多个 SQL 命令(如多个 COMMENT 语句用分号分隔)。
解决方案
将所有多行 COMMENT 语句拆分为单独的 op.execute() 调用。
修改前
op.execute("""
COMMENT ON TABLE folder_shares IS '文件夹分享表';
COMMENT ON COLUMN folder_shares.id IS '分享记录ID (UUID v7)';
COMMENT ON COLUMN folder_shares.folder_id IS '文件夹ID(逻辑外键,无物理约束)';
...
""")
修改后
op.execute("COMMENT ON TABLE folder_shares IS '文件夹分享表'")
op.execute("COMMENT ON COLUMN folder_shares.id IS '分享记录ID (UUID v7)'")
op.execute("COMMENT ON COLUMN folder_shares.folder_id IS '文件夹ID(逻辑外键,无物理约束)'")
...
变更内容
文件:server/alembic/versions/20260129_1410_create_folder_shares_and_export_jobs.py
- folder_shares 表注释:拆分为 14 个独立的
op.execute()调用 - folder_export_jobs 表注释:拆分为 18 个独立的
op.execute()调用
验证结果
迁移执行成功
$ docker exec jointo-server-app alembic current
20260129_1410 (head)
表结构验证
folder_shares 表:
- ✅ 13 个字段
- ✅ 5 个索引(包括主键)
- ✅ 4 个约束检查
- ✅ 使用 TIMESTAMPTZ 类型
- ✅ 使用 SMALLINT 枚举
folder_export_jobs 表:
- ✅ 17 个字段
- ✅ 5 个索引(包括主键)
- ✅ 2 个约束检查
- ✅ 使用 TIMESTAMPTZ 类型
- ✅ 使用 SMALLINT 枚举
技术说明
asyncpg 限制
asyncpg 使用 prepared statements 来提高性能,但这要求每个 statement 只能包含一个 SQL 命令。当使用分号分隔多个命令时,会触发此错误。
最佳实践
在 Alembic 迁移中使用 asyncpg 时:
- 单个命令:每个
op.execute()只执行一个 SQL 命令 - 避免分号:不要在一个字符串中用分号分隔多个命令
- 批量操作:如果需要执行多个相似命令,使用循环
# ✅ 推荐
for column in columns:
op.execute(f"COMMENT ON COLUMN {table}.{column} IS '{comment}'")
# ❌ 避免
op.execute("""
COMMENT ON COLUMN table.col1 IS 'comment1';
COMMENT ON COLUMN table.col2 IS 'comment2';
""")
相关文档
总结
通过将多行 COMMENT 语句拆分为独立的 op.execute() 调用,成功解决了 asyncpg 的 prepared statement 限制问题。迁移现已正常执行,两个新表(folder_shares 和 folder_export_jobs)已成功创建。