【问题标题】:How to quote/escape identifiers such as column names with JDBC?如何使用 JDBC 引用/转义标识符,例如列名?
【发布时间】:2010-01-10 19:04:42
【问题描述】:

不同的数据库服务器使用不同的方式来引用和转义标识符。

例如"foo bar" vs `foo bar` vs [foo bar], or "10""" vs "10\"", 或者 FooBar 或数组之类的标识符需要为某些数据库引用,但对于其他数据库则不需要。

是否有任何 API 方法可以为给定的数据库连接正确执行引用/转义?或者任何替代解决方案?

【问题讨论】:

    标签: java jdbc


    【解决方案1】:

    看看

    DatabaseMetaData.getIdentifierQuoteString()
    

    我没用过,但听起来不错:-)

    getExtraNameCharacters() 也可以提供一些帮助

    【讨论】:

    • 不是一个完整的解决方案,但绝对有用!
    • @aditsu 我不明白这不是一个完整的解决方案。
    • @raven 很好,例如它对转义根本没有帮助
    • @raven,使用这些方法,程序员仍然需要手动完成工作。
    • DatabaseMetaData#getSQLKeywords() 也很有用(例如,知道哪些字符串不需要引用)。
    【解决方案2】:

    从 Java 9 开始,Statement 接口为特定引擎的引用提供了多种方法:

    • enquoteIdentifier 用于 SQL 标识符(例如架构、表、列名)
    • enquoteLiteral 用于字符串文字(例如 char、varchar、文本文字)
    • enquoteNCharLiteral 用于国家字符集文字
    Statement stmt = connection.createStatement();
    String query = String.format(
            "SELECT id FROM %s WHERE name = %s",
            stmt.enquoteIdentifier("table", false),
            stmt.enquoteLiteral("it's"));
    ResultSet resultSet = stmt.executeQuery(query);
    

    但是,只要有可能(即对于数据查询中的值),请改用准备好的语句。

    Statement stmtFormat = connection.createStatement();
    String query = String.format(
            "SELECT id FROM %s WHERE name = ?", 
            stmtFormat.enquoteIdentifier("table", false);
    PreparedStatement stmt = connection.prepareStatement(query);
    stmt.setString(1, "it's");
    ResultSet resultSet = stmt.executeQuery();
    

    【讨论】:

      【解决方案3】:

      我认为您的问题的答案是,如果您正在使用 JDBC 编写与数据库无关的应用程序,那么您需要使用与数据库无关的名称,而不是需要每个数据库供应商进行特殊转义的名称。

      在支持它的 JDBC 中我一无所知。 ORM 产品会处理这些事情。

      编辑:如果您正在编写 ORM,那么我认为每个支持的数据库都需要一个单独的 SQL 生成类,只是为了处理所涉及的各种语法,所以您必须编写它。您当然可以查看各种开源 ORM 的源代码,看看它们是如何处理的。

      【讨论】:

      • 关于数据库中性名称的好点,但仍然会出现意外(例如,某个标识符在另一个数据库中可能不可接受)。另外,如果我……实际上是在写一个 ORM 怎么办?是否需要为每个受支持的数据库单独手动编码引用/转义实现?
      • 遵守 SQL 标准中的标识符命名规则。这些将在任何地方工作。
      • @PaulTomblin 嘿,是的,“标准”。规范中有很大的灵活性——供应商添加了他们自己的关键字和保留字,如果应用程序要使用它们,必须引用它们。我同意尝试遵守规范是最不痛苦的选择,但是 很糟糕 JDBC 没有公开 java.sql.Connection.quoteIdentifier(...)DatabaseMetaData.quoteIdentifier(...) 方法和支持 SPI,因为这意味着你总是在做保留字的舞蹈。 getIdentifierQuoteString 不做这项工作,它不表达引用规则。
      • @CraigRinger 我将我之前的评论修改为“坚持标准,并改掉你从使用 MySQL 中养成的坏习惯 - 这是一种可憎的东西,它不是 SQL”。在 Oracle、Sybase、Postgres 甚至 SQLlite 上执行 SQL 的 20 多年中,我从来没有引用过标识符。
      • @PaulTomblin Heh,这里是 PostgreSQL 专用用户。在 Pg 的解析器难以区分未保留的关键字和用户标识符的情况下,有时对我来说是必要的,但总的来说它并没有太大的问题。我只是对 JDBC 规范使得应用程序防御性地引用标识符以及 JDBC 驱动程序公开其正确引用知识的难度感到恼火。 (除非您是 MySQL 或 MS SQL Server,否则无论如何都是 ANSI SQL 引用)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-11-16
      • 1970-01-01
      • 1970-01-01
      • 2021-11-02
      • 2023-04-11
      • 2011-05-25
      相关资源
      最近更新 更多