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

修复文件夹迁移的 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

  1. folder_shares 表注释:拆分为 14 个独立的 op.execute() 调用
  2. 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 时:

  1. 单个命令:每个 op.execute() 只执行一个 SQL 命令
  2. 避免分号:不要在一个字符串中用分号分隔多个命令
  3. 批量操作:如果需要执行多个相似命令,使用循环
# ✅ 推荐
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)已成功创建。