You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在psycopg3的Alembic迁移中执行事务外的语句?

使用Alembic + Psycopg3执行REINDEX CONCURRENTLY触发AssertionError的解决方案

问题场景

尝试通过Alembic的autocommit_block执行PostgreSQL的REINDEX INDEX CONCURRENTLY(该命令无法在事务内运行),代码如下:

with op.get_context().autocommit_block():
    op.execute("REINDEX INDEX CONCURRENTLY idx_something")

但在Psycopg3环境下触发AssertionError,报错详情:

@contextmanager
def autocommit_block(self) -> Iterator[None]:
    # ...
    _in_connection_transaction = self._in_connection_transaction()

    if self.impl.transactional_ddl and self.as_sql:
        self.impl.emit_commit()

    elif _in_connection_transaction:
>       assert self._transaction is not None
E       AssertionError

.venv/lib/python3.10/site-packages/alembic/runtime/migration.py:330: AssertionError

环境版本

  • Psycopg 3.2.9
  • Alembic 1.16.4
  • SQLAlchemy 2.0.42

问题原因

这是Alembic与Psycopg3的兼容性问题:Alembic的autocommit_block逻辑检查到连接处于事务中,但无法找到对应的_transaction对象引用,触发断言失败。

可行解决方案

绕过Alembic的autocommit_block,手动控制连接的自动提交状态,直接操作原始连接:

方案一:使用SQLAlchemy连接操作

from sqlalchemy import text

# 获取绑定的数据库连接
conn = op.get_bind().connect()
try:
    # 切换到自动提交模式
    conn.execution_options(isolation_level="AUTOCOMMIT")
    # 执行REINDEX命令
    conn.execute(text("REINDEX INDEX CONCURRENTLY idx_something"))
finally:
    # 恢复默认隔离级别,避免影响后续迁移步骤
    conn.execution_options(isolation_level="READ COMMITTED")
    conn.close()

方案二:直接使用Psycopg3原生连接

# 获取SQLAlchemy连接,再拿到Psycopg3原生连接
sa_conn = op.get_bind()
pg_conn = sa_conn.connection
try:
    # 开启自动提交
    pg_conn.autocommit = True
    with pg_conn.cursor() as cur:
        cur.execute("REINDEX INDEX CONCURRENTLY idx_something")
finally:
    # 恢复自动提交状态
    pg_conn.autocommit = False

说明

两种方案都直接避开了Alembic的事务管理逻辑,确保REINDEX CONCURRENTLY在自动提交模式下执行,既满足PostgreSQL的命令要求,又不会触发Alembic内部的断言错误。

内容的提问来源于stack exchange,提问作者Joel Shellman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 13:24:52