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

如何使用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和属性笔误,可按需修复:

  1. 金额输入框的label属性for="amountt"笔误,改为for="amount"和输入框id对应
  2. CSS中margin-left:500spx笔误,改为margin-left:500px
  3. CSS中li下的a标签样式漏了选择器,补上li a {即可

验证方式

  1. 安装依赖后启动服务:node server.js
  2. 浏览器访问http://localhost:8084打开转账表单
  3. 填入数据库中已存在的转出、收款账户名,填写合法金额提交,即可看到两个账户余额对应更新
  4. 测试异常场景:填不存在的账户、余额不足的金额、相同的转出转入账户,都会收到明确的错误提示,不会出现脏数据

内容的提问来源于stack exchange,提问作者blank ez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 00:15:54