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

Vert.x PgClient预查询传参错误:参数数量不匹配问题排查

问题分析与解决方案

咱们一步一步拆解问题根源,再给出修复方案:

核心问题1:根本没传递参数给查询

你看业务层代码里的execute(ar -> {...}),这个方法调用完全没传入任何参数!Vert.x的preparedQuery执行时,必须把参数通过execute方法传进去,不然数据库收到的查询就没有参数值,自然会报错“实际参数数量为0”。

核心问题2:SQL里的$3、$4被当成了字符串字面量

你的SQL语句中,substring(art.codigobarra,1,2) = '$3'这里的'$3'是带单引号的,PostgreSQL会把它当作固定字符串$3,而不是参数占位符。所以数据库只能识别到$1和$2两个有效占位符,这就是报错里“预期参数数量为2”的原因。


修复步骤

1. 修正SQL语句

去掉$3、$4外面的单引号,让它们成为真正的参数占位符:

private static final String SELECT_CBA = "select art.leyenda, $1::numeric(10,3) as cantidad, uni.abreviatura, \r" + 
    "round(((art.precio_costo * (art.utilidad_fraccionado/100)) + art.precio_costo) * $2::numeric(10,3),2) as totpagar \r" + 
    "FROM public.articulos art join public.unidades uni on uni.idunidad = art.idunidad \r" + 
    "WHERE (substring(art.codigobarra,1,2) = $3 and substring(art.codigobarra,3,6) = $4)";

2. 补全参数传递与类型转换

从路由中提取参数,转换成SQL需要的类型,再传递给execute方法:

public void getOneReadingBarcode(RoutingContext routingContext) {
    HttpServerResponse response = routingContext.response();
    
    // 从路由路径中提取参数
    String cantComp1Str = routingContext.pathParam("cantcomp1");
    String cantComp2Str = routingContext.pathParam("cantcomp2");
    String tipoProd = routingContext.pathParam("tipoprod");
    String prodPadre = routingContext.pathParam("prodpadre");
    
    // 把字符串参数转成数值类型($1、$2需要numeric,这里用Double示例,建议用BigDecimal处理精确数值)
    try {
        Double cantComp1 = Double.parseDouble(cantComp1Str);
        Double cantComp2 = Double.parseDouble(cantComp2Str);
        
        // 按SQL占位符顺序组装参数
        Tuple params = Tuple.of(cantComp1, cantComp2, tipoProd, prodPadre);
        
        pgClient
            .preparedQuery(SELECT_CBA)
            .execute(params, ar -> {
                if (ar.succeeded()) {
                    RowSet<Row> rows = ar.result();
                    if (!rows.isEmpty()) {
                        Row row = rows.iterator().next();
                        JsonObject result = new JsonObject()
                            .put("leyenda", row.getString("leyenda"))
                            .put("cantidad", row.getDouble("cantidad"))
                            .put("abreviatura", row.getString("abreviatura"))
                            .put("totpagar", row.getDouble("totpagar"));
                        response.putHeader("Content-Type", "application/json")
                               .end(result.encode());
                    } else {
                        response.setStatusCode(404)
                               .end("未找到匹配的商品");
                    }
                } else {
                    response.setStatusCode(500)
                           .end("查询失败: " + ar.cause().getMessage());
                }
            });
    } catch (NumberFormatException e) {
        // 处理参数格式错误
        response.setStatusCode(400)
               .end("数值参数格式错误: " + e.getMessage());
    }
}

为什么这样修复?

  • 去掉单引号后,PostgreSQL会正确识别4个参数占位符,和你传入的4个参数一一对应;
  • 传递参数后,PgClient会自动处理字符串类型的转义与引号包裹,避免SQL注入风险;
  • 类型转换确保了参数和SQL定义的numeric类型匹配,不会出现类型不兼容的问题。

内容的提问来源于stack exchange,提问作者Ernesto Andres Zapata Icart

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 09:07:46