Node.js+node-postgres实现PSQL库重建脚本仅隔次运行成功如何解决?
问题根因
- 异步执行顺序错乱:
deleteDb和createDbAndTables内部的pool.query都是异步回调逻辑,直接先后调用两个函数并不会等删除操作完成再执行创建,二者是并发执行的,就会出现两种交替的结果:- 删除操作先完成,再执行创建,流程正常
- 创建操作先执行成功,随后删除操作把刚建好的库删掉,后续连接
abc库时就会报库不存在的错误,刚好对应“每隔一次运行成功”的现象
- 错误捕获不完整:
CREATE DATABASE操作的回调没有判断错误参数,不管库是否创建成功,都会直接初始化客户端连接abc库,创建失败时自然会报错 - 建表逻辑资源泄漏:循环建表的回调中判断
i == tables.length永远不成立(循环变量i最大为tables.length-1),导致client.end()始终不会执行,残留的abc库活跃连接会导致下一次删库失败(PostgreSQL禁止删除存在活跃连接的数据库)
修复代码
推荐使用node-postgres支持的Promise + async/await写法,替代回调逻辑,保证执行顺序:
const { Pool, Client } = require('pg') const dbName = "abc" const tables = [{ name: "users", content: "id SERIAL, username VARCHAR, email VARCHAR, passcode VARCHAR" }] // 连接默认的postgres库执行库级操作 const pool = new Pool({ user: 'postgres', host: 'localhost', database: 'postgres', password: 'postgres', port: 5432 }) async function initDb() { try { // 删之前先断开所有连接到目标库的活跃会话 await pool.query(` SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = $1 AND pid <> pg_backend_pid() `, [dbName]) await pool.query(`DROP DATABASE IF EXISTS ${dbName}`) console.log(`deleted db ${dbName}`) // 执行建库 await pool.query(`CREATE DATABASE ${dbName}`) console.log(`created db ${dbName}`) await pool.end() // 连接新建的库建表 const client = new Client({ host: 'localhost', port: 5432, user: 'postgres', password: 'postgres', database: dbName, }) await client.connect() for (const table of tables) { await client.query(`CREATE TABLE ${table.name} (${table.content})`) console.log(`created table ${table.name}`) } await client.end() console.log('all operations completed') } catch (err) { console.error('operation failed:', err) // 出错也要主动关闭连接,避免进程挂起 await pool.end() process.exit(1) } } initDb()
可优化点
- 所有数据库配置抽离到环境变量,避免硬编码账号密码,降低安全风险
- 表结构定义可以补充主键、索引、非空等约束,避免后期业务逻辑出现数据异常
- 可以新增幂等判断,支持按需跳过已有表的创建,适配迭代开发场景
- 涉及动态拼接的表名、字段名建议做白名单校验,避免SQL注入风险
- 可以添加分级日志,方便后续定位执行过程中的异常问题
内容的提问来源于stack exchange,提问作者Carson Burke
相关产品推荐
相关产品推荐

