程序从数据库读取值为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
相关产品推荐
相关产品推荐

