如何转义 JDBC 预准备语句中的文字问号 ('?')

2022-09-04 05:21:06

我想创建一个JDBC PreparedStatement,如下所示:

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

其中 1 个是文本,第 2 个是参数。我可以用它来代替,但我认为额外的函数调用会减慢SQL的执行速度。有没有办法逃脱第一个???CHAR(63)'?'?

编辑:

下面的代码测试 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规范,找不到任何提及参数标记如果位于引号内将被忽略的提及,但是我发现的ReadyStatement解析器的少数实现(MySqlc-JDBCH2)似乎都排除了单引号中的文本作为参数标记。?


答案 1

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

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

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


答案 2

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

ps.setString(1, "?");

推荐