使用db-migrate删除PostgreSQL测试库失败及migrations表为空问题咨询
我在Node.js应用中使用npm包db-migrate对PostgreSQL数据库执行迁移操作,测试完成后希望删除额外的测试数据库。最初在package.json中添加了如下测试脚本:
"test": "set ENV=test&& npx tsc && db-migrate --env test up && jasmine && db-migrate db:drop --env test test_database_name"
执行该脚本时遇到错误:
Error: Failed to drop database! error: cannot drop the currently open database
我原以为是IDE(IntelliJ)的数据库管理工具连接着测试库导致的,但即使断开或移除该连接,错误仍存在。因此我尝试了替代脚本:
"test": "set ENV=test&& npx tsc && db-migrate --env test up && jasmine && db-migrate --env test reset"
据我了解,脚本最后一条命令会删除测试库、重新创建并执行所有迁移。该脚本看似运行正常,我可保持与测试库的连接,所有表都被删除,但最终测试库中仅剩下一张空的migrations表。我原本预期会看到数据库重建后执行的所有迁移记录,为何该表是空的?
一、db:drop报错的根本原因
PostgreSQL禁止删除当前有活跃连接的数据库,哪怕这个连接是db-migrate自己创建的。你断开IDE连接没用,是因为db-migrate执行完up命令后,没有主动释放与测试库的连接,导致后续db:drop执行时,数据库仍被该进程占用,触发了报错。
二、reset命令后migrations表为空的原因
你对reset命令的理解有误,它不会删除并重建数据库,实际执行逻辑是:
- 依次运行所有迁移脚本的
down操作(把数据库回滚到初始状态) - 重新运行所有迁移脚本的
up操作
migrations表为空,是因为第一步回滚操作会把所有已执行的迁移记录从该表中移除;如果后续重跑up时出现隐性错误(比如脚本执行中断、权限问题),或者你的迁移脚本up逻辑有问题,就会导致migrations表没有被重新填充。
三、推荐的测试后清理方案
1. 强制断开连接再删库
修改脚本,先通过PostgreSQL命令强制终止测试库的所有活跃连接,再执行db:drop:
"test": "set ENV=test&& npx tsc && db-migrate --env test up && jasmine && psql -U your_db_user -c 'SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = ''test_database_name'';' && db-migrate db:drop --env test test_database_name"
记得把your_db_user替换为你的PostgreSQL用户名。
2. 使用fresh命令(版本支持的话)
部分新版本的db-migrate提供了fresh命令,它会直接删除数据库、重建数据库,再执行所有迁移,逻辑更贴合你的需求:
"test": "set ENV=test&& npx tsc && db-migrate --env test fresh && jasmine"
四、如果坚持用reset的排查方法
- 执行
db-migrate --env test reset --verbose查看详细执行日志,确认up步骤是否完整执行 - 检查迁移脚本的
down操作,确保没有误删migrations表本身 - 验证测试库的权限,确保
db-migrate有足够权限写入migrations表记录
内容的提问来源于stack exchange,提问作者Luk

