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

程序从数据库读取值为0而非预期1,代码问题排查求助

问题分析与解决方案

哦,我一眼就看穿问题所在了——你误用了PreparedStatement的占位符!这是JDBC新手常踩的坑,咱们一步步拆解:

核心问题:占位符不能替代列名

PreparedStatement里的?占位符有严格的使用场景:它只能用来替换SQL中的值(比如WHERE id = ?里的id值),绝对不能用来替换表名、列名这类数据库对象的标识符。

你当前的代码中,把列名eleccion(也就是Provincial)放在了第一个占位符里,JDBC会把它当作一个字符串常量来处理。也就是说,实际执行的SQL是:

SELECT 'Provincial' FROM votos WHERE id = 1

这时候返回的结果是字符串'Provincial',当你调用res->getInt(1)时,JDBC尝试把这个字符串转换成整数,转换失败就默认返回0了——这就是你看到异常结果的原因!

修复方案

既然占位符不能用在列名上,我们需要换一种方式动态指定列名,同时要注意避免SQL注入风险:

方案1:固定列名白名单校验(推荐)

如果eleccion的可选值是固定的几个(比如只有Provincial、Nacional这类),可以先做合法性校验,再拼接SQL:

// 先校验列名是否合法,避免SQL注入
if (!"Provincial".equals(eleccion) && !"Nacional".equals(eleccion)) {
    throw new IllegalArgumentException("非法的列名:" + eleccion);
}
// 拼接合法的SQL语句
String sql = "SELECT " + eleccion + " FROM votos WHERE id = ?";
pstmt = con->prepareStatement(sql);
pstmt->setInt(1, p->getId());
res = pstmt->executeQuery();
while(res->next()) {
    p->setVoto(res->getInt(1));
}

方案2:通过数据库元数据验证列名

如果列名的可选范围很大,可以查询数据库表的元数据,验证eleccion是否是votos表的有效列名,再拼接SQL,这样安全性更高:

// 获取表的元数据,验证列名是否存在
DatabaseMetaData metaData = con->getMetaData();
ResultSet columns = metaData->getColumns(null, null, "votos", eleccion);
if (!columns->next()) {
    throw new IllegalArgumentException("不存在的列名:" + eleccion);
}
// 拼接SQL并执行
String sql = "SELECT " + eleccion + " FROM votos WHERE id = ?";
pstmt = con->prepareStatement(sql);
pstmt->setInt(1, p->getId());
// 后续查询逻辑不变

验证方法

你可以开启JDBC的SQL日志(比如MySQL驱动可以通过logger=com.mysql.cj.log.Slf4JLogger开启),就能看到实际执行的SQL语句,直观确认占位符被替换后的效果,也能帮你更快定位这类问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:08:04