为什么Python Alembic对PostgreSQL迁移后残留锁阻碍后续迁移?
问题原因
锁残留的核心原因是PostgreSQL的锁是绑定到数据库连接会话的,只要连接没有物理关闭,会话内未结束的事务持有的锁就不会释放,结合你提供的代码,具体触发点如下:
- SQLAlchemy默认启用连接池机制:
create_engine默认会创建大小为5的连接池,你通过with connectable.connect()创建的连接,在退出with块后只会被归还到连接池,不会直接物理关闭。如果这个连接上还有未完全终止的事务,对应的锁就会一直被持有。 - 事务状态残留:你虽然通过
context.begin_transaction()包裹了迁移逻辑,但Alembic的上下文事务提交后,连接本身默认autocommit=False,如果存在迁移脚本里的自定义查询没有被事务包裹、或者隐式开启的事务没有被提交,就会导致会话一直处于挂起的事务状态,锁无法释放。 - 你给迁移用户授予了
db_owner角色,如果迁移过程中执行了SET ROLE db_owner这类会话级配置,连接归还到池的时候会话状态不会被重置,也会加剧锁残留的概率。
解决方案
针对迁移这类一次性执行的场景,不需要复用连接,直接按如下修改代码即可根治:
- 引入
NullPool禁用连接池,让连接用完就直接物理关闭:
from sqlalchemy.pool import NullPool # 创建引擎时指定poolclass参数 connectable = create_engine(get_conn_url_from_env(), poolclass=NullPool)
- 事务结束后手动提交清空连接状态,在上下文事务块结束后补充提交逻辑:
with context.begin_transaction(): context.run_migrations() # 手动提交确保所有事务终止 connection.commit()
- 如果是在常驻进程中调用迁移逻辑,执行完迁移后主动终止进程,避免连接资源被持有。
内容的提问来源于stack exchange,提问作者swagrov
相关产品推荐
相关产品推荐

