JDBC PreparedStatement 似乎忽略占位符

Posted

技术标签:

【中文标题】JDBC PreparedStatement 似乎忽略占位符【英文标题】:JDBC PreparedStatement Seems to Ignore Placeholder 【发布时间】:2017-09-22 17:13:48 【问题描述】:

鉴于PreparedStatement 的以下代码,我使用占位符 (?) 来填充 String

String sql = "SELECT SUM(Premium), SUM(AgentComm)\n" +
                "FROM \"?_KLCommissions\" \n" +
                "WHERE AgentCode = \"?\";";

    PreparedStatement preparedStatement = conn.prepareStatement(sql);
    preparedStatement.setString(1, year);
    preparedStatement.setString(2, agent.getAgentNumber());

    ResultSet resultSet = preparedStatement.executeQuery();

但是,在执行查询时,我收到一条 SQL 错误:no such table: ?_KLCommissions

为什么在处理查询时? 占位符没有被替换?

【问题讨论】:

【参考方案1】:

双引号中包含它,这意味着它不是占位符 - 它只是值的一部分。

除此之外,大多数 SQL 数据库不允许您将参数用于表名和列名等参数 - 只有 可以参数化。所以你可能需要直接构建表名部分,然后使用

WHERE AgentCode = ?

对于代理代码 - 因此您只需设置一个参数。所以像:

String tableName = year + "_KLCommissions";
// TODO: Put validation here unless you already have *complete confidence*
// that the value of "year" can't be messed around with.
String sql = "SELECT SUM(Premium), SUM(AgentComm) " +
             "FROM " + tableName + " " +
             "WHERE AgentCode = ?";

PreparedStatement preparedStatement = conn.prepareStatement(sql);
preparedStatement.setString(1, agent.getAgentNumber());
ResultSet resultSet = preparedStatement.executeQuery();

请注意那里的 TODO - 您真的不希望用户能够为 year 提供任意值,因为这样他们就可以在您的查询中添加任意 SQL。

【讨论】:

因此,例如,如果我需要使用不同的年份多次运行该语句,我实际上需要多个语句来代替吗? @Zephyr:是的,你会的。 请注意,SQLite 不允许表名以数字开头而不用双引号转义名称。 @MickMnemonic 我使用单引号以 int 开头的表名;这似乎也很好。谢谢你,乔恩。我不知道占位符的限制!

以上是关于JDBC PreparedStatement 似乎忽略占位符的主要内容,如果未能解决你的问题,请参考以下文章

Java -- JDBC 学习--PreparedStatement

JDBC 似乎在我的数字周围加上了单引号

JDBC - 语句、PreparedStatement、CallableStatement 和缓存

JDBC封装学习笔记---面向对象的JDBC,使用preparedStatement

JDBC深入理解Statement和PreparedStatement

jdbc防止sql注入-PreparedStatement