如何在 JDBC 准备好的语句中转义文字问号(“?”)

问题描述 投票:0回答:5

我想创建一个 JDBC 准备语句,例如:

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
5个回答
30
投票

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

来自使用Statement或PreparedStatement接口

在 JDBC 中,问号 (

?
) 是位置占位符
PreparedStatement
的参数。然而,有一些 包含问号的 PostgreSQL® 运算符。为了保持这样的 SQL 语句中的问号被解释为 位置参数,使用两个问号(
??
)作为转义 顺序。您还可以在
Statement
中使用此转义序列,但是 这不是必需的。具体来说,仅在
Statement
单个 (
?
) 可用作运算符。


9
投票

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

String
?
,

ps.setString(1, "?");

5
投票

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

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

所以逃避是没有必要(也不可能)的。

然而,这只是理论,不幸的是,在实践中它并不像 PostgreSQL JDBC 驱动程序那样工作。为了解决这个问题,最新版本的 PostgreSQL 驱动程序提供了一个选项,可以使用

??
来转义不是参数占位符的问号。


3
投票

你尝试过吗?我认为引用问号是可以的。在准备好的声明中只有“裸”问号应该被替换


2
投票

我在查询中使用了

CHR(63)
,这有助于解决我的问题。 (十进制 63 是 ASCII 中的问号。

以下是我所做的示例:

select q'[<div id=['|"]TRD_%%GEN%%['|"].*]' || chr(63) || q'[</div>]' from dual;

这有助于将字符串获取为:

<div id=['|"]TRD_%%GEN%%['|"].*?</div>

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

CHR 函数是一个内置函数,可以像其他 Oracle 函数一样使用。如果您知道查询不会重复很多次,则可以使用此功能。

© www.soinside.com 2019 - 2024. All rights reserved.