如何使用Node.js将HTML表单数据提交更新至PostgreSQL数据库
PostgreSQL 转账余额更新问题修复方案
参考资源
问题根因
你写的两条UPDATE语句无法执行,核心问题有以下几个:
- 语句中使用的
amount/from/to变量未定义,表单提交的参数存储在request.body对象中,你之前仅打印了日志未做取值 - POST路由处理函数为普通同步函数,
pool.query是异步Promise调用,未使用await/.then()的情况下既不会等待SQL执行完成,也无法捕获执行报错 - 两步UPDATE操作未加数据库事务,一旦出现扣款成功、入账失败的异常情况,会导致账务数据不一致
- 代码存在冗余逻辑:手动调用
pool.connect()预连接没有必要,PG连接池会在首次查询时自动建立连接;app.listen日志打印的端口为8080,实际监听端口是8084,容易造成误导 - 表单传递的
amount参数为字符串类型,未做类型转换和合法性校验,极端场景下会触发SQL执行异常 - 未做业务规则校验:未判断转出账户余额是否充足、转出/转入账户是否存在、两个账户是否为同一账户,会导致数据不符合业务预期
修正后代码
server.js 完整修正版
把原有server.js替换为以下代码:
const { Pool } = require('pg'); const express = require('express'); const app = express(); // 解析请求体 app.use(express.json()); app.use(express.urlencoded({ extended: true })); // 初始化PG连接池 const pool = new Pool({ user: 'postgres', host: 'localhost', database: 'postgres', password: 'wasay123', port: 5432, }); // 渲染表单页面 app.get("/", (req, res) => res.sendFile(`${__dirname}/web.html`)); // 处理转账提交 app.post("/", async function(request, response) { const client = await pool.connect(); try { // 从表单参数中取值 const { from, to, amount: amountStr } = request.body; const amount = Number(amountStr); // 基础参数合法性校验 if (!from || !to || !amount || amount <= 0) { return response.status(400).send('参数错误:请填写正确的转出账户、收款账户和大于0的转账金额'); } if (from.trim() === to.trim()) { return response.status(400).send('参数错误:转出账户和收款账户不能相同'); } // 开启数据库事务 await client.query('BEGIN'); // 扣减转出账户余额,同时校验余额是否充足 const deductResult = await client.query( 'UPDATE "accounts" SET "balance" = "balance" - $1 WHERE "name" = $2 AND "balance" >= $1 RETURNING *', [amount, from.trim()] ); if (deductResult.rowCount === 0) { await client.query('ROLLBACK'); return response.status(400).send('转账失败:转出账户不存在或账户余额不足'); } // 增加收款账户余额 const addResult = await client.query( 'UPDATE "accounts" SET "balance" = "balance" + $1 WHERE "name" = $2 RETURNING *', [amount, to.trim()] ); if (addResult.rowCount === 0) { await client.query('ROLLBACK'); return response.status(400).send('转账失败:收款账户不存在'); } // 所有操作成功,提交事务 await client.query('COMMIT'); console.log(`转账成功:从${from}向${to}转账${amount}`); response.send(`转账成功!<br><a href="/">返回继续转账</a>`); } catch (err) { // 出现异常回滚事务 await client.query('ROLLBACK'); console.error('转账执行异常:', err); response.status(500).send('服务器内部错误,转账未执行'); } finally { // 释放数据库连接回连接池 client.release(); } }); // 启动服务 app.listen(8084, () => console.log("Web server is listening on port 8084"));
web.html 可选修复(不修复不影响核心功能,仅修正笔误)
原有HTML文件存在几处CSS和属性笔误,可按需修复:
- 金额输入框的label属性
for="amountt"笔误,改为for="amount"和输入框id对应 - CSS中
margin-left:500spx笔误,改为margin-left:500px - CSS中li下的a标签样式漏了选择器,补上
li a {即可
验证方式
- 安装依赖后启动服务:
node server.js - 浏览器访问
http://localhost:8084打开转账表单 - 填入数据库中已存在的转出、收款账户名,填写合法金额提交,即可看到两个账户余额对应更新
- 测试异常场景:填不存在的账户、余额不足的金额、相同的转出转入账户,都会收到明确的错误提示,不会出现脏数据
内容的提问来源于stack exchange,提问作者blank ez
相关产品推荐
相关产品推荐

