【问题标题】:How do I escape a literal question mark ('?') in a JDBC prepared statement如何在 JDBC 准备语句中转义文字问号 ('?')
【发布时间】:2014-12-18 10:04:08
【问题描述】:

我想创建一个 JDBC PreparedStatement,例如:

SELECT URL,LOCATE ( '?', URL ) pos FROM Links WHERE pageId=? ORDER BY pos ASC

第一个? 是文字,第二个? 是参数。我可以使用CHAR(63) 代替'?',但我认为额外的函数调用会减慢SQL 的执行速度。有什么办法可以逃脱第一个?

编辑:

以下代码测试 dkatzel 的断言,即字符串中的 ? 字符不被视为标记:

public class Test {
    public static void main(String[] args) throws SQLException {
        Connection conn = DriverManager.getConnection("jdbc:h2:mem:test");
        Statement stmt = conn.createStatement();
        stmt.executeUpdate("CREATE TABLE Links(URL VARCHAR(255) PRIMARY KEY,pageId BIGINT)");
        stmt.executeUpdate("INSERT INTO Links(URL,pageId) VALUES('http://foo.bar?baz',1)");
        stmt.executeUpdate("INSERT INTO Links(URL,pageId) VALUES('http://foo.bar/baz',1)");
        stmt.close();
        PreparedStatement ps = conn
            .prepareStatement("SELECT URL,LOCATE ( '?', URL ) pos FROM Links WHERE pageId=? ORDER BY pos ASC");
         ps.setLong(1, 1);
        ResultSet rs = ps.executeQuery();
        while (rs.next()) {
            System.out.println(rs.getString(1) + ":" + rs.getInt(2));
        }
        rs.close();
        ps.close();
        conn.close();
    }
}

输出:

http://foo.bar/baz:0
http://foo.bar?baz:15

看来 dkatzel 是正确的。我搜索了JDBC Spec,但找不到任何提及?参数标记如果在引号内将被忽略,但我发现的PreparedStatement解析器的少数实现(MySqlc-JDBCH2 ) 似乎都将单引号内的文本排除在参数标记之外。

【问题讨论】:

标签: java sql jdbc prepared-statement


【解决方案1】:

你试过了吗?我认为引用的问号是可以的。在准备好的语句中应该只替换“裸”问号

【讨论】:

  • 我编辑了操作以包含一个测试...这证实了您的建议是正确的。
【解决方案2】:

如果它不适用于您的 JDBC 驱动程序,您可以将其绑定为 String ?

ps.setString(1, "?");

【讨论】:

    【解决方案3】:

    ? 的含义在 SQL 规范中指定,对此 JDBC 规范遵循 SQL 规范。

    驱动程序不会(也不应该)将文字中的问号解释为参数占位符,因为字符串文字中的问号只是字符串文字中的一个字符。有关详细信息,请参阅 SQL:2011 Foundation (ISO-9075-2:2011) 第 5 章。

    所以转义不是必要的(也不可能)。

    【讨论】:

    【解决方案4】:

    我在查询中使用了 CHR(63),这有助于解决我的问题。

    这是我做的例子: select q'[<div id=['|"]TRD_%%GEN%%['|"].*]' || chr(63) || q'[</div>]' from dual;

    这有助于将字符串获取为: <div id=['|"]TRD_%%GEN%%['|"].*?</div>

    然后我在插入语句中使用了这个查询,并运行了 PreparedStatement。工作得很好。

    CHR 函数是一个内置函数,可以与其他 oracle 函数类似地使用。如果您知道查询不会重复很多次,则可以使用它。

    【讨论】:

      【解决方案5】:

      根据您使用的 JDBC 驱动程序,您可以通过添加另一个问号来转义,例如如果你使用的是 PostgreSQL

      https://jdbc.postgresql.org/documentation/head/statement.html

      在 JDBC 中,问号 (?) 是 PreparedStatement 位置参数的占位符。但是,有许多 PostgreSQL 运算符包含问号。要防止 SQL 语句中的此类问号被解释为位置参数,请使用两个问号 (??) 作为转义序列。您也可以在语句中使用此转义序列,但这不是必需的。具体来说,只有在语句中,单个 (?) 可以用作运算符。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-01-19
        • 1970-01-01
        • 2021-12-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-10
        • 2011-08-06
        相关资源
        最近更新 更多