如何在 liquibase OracleDatabase 中添加保留关键字?

How to add reserved keywords in liquibase OracleDatabase?

尝试使我的 spring 引导 JPA 应用程序与 Oracle DB 兼容,已经 运行 MySQL 和 H2。 不幸的是,liquibase 生成的数据使用了一些 Oracle 的保留关键字作为 table 或列名。

好消息是 hibernate 和 liquibase 实现可以检测到这些关键字并在查询数据库时“引用”它们(对 liquibase 使用 objectQuotingStrategy="QUOTE_ONLY_RESERVED_KEYWORDS",对 hibernate 使用 spring.jpa.properties.hibernate.auto_quote_keyword: true)。 坏消息是 hibernate 和 liquibase 不共享相同的 Oracle 保留关键字列表。

例如,value 不被 liquibase 识别为保留关键字,但被 hibernate(使用 ANSI SQL:2003 关键字)识别为保留关键字。 我的一个 liquibase changeSets 创建了一个带有小写 value 列的 table,因此 Liquibase 创建了带有未加引号的小写 value[=] 的 table 40=] 列,Oracle DB 自动将其转换为大写 VALUE 列。现在当休眠试图获取 该列,它识别 value 并引用它 (`SELECT "value" from ...),这使其区分大小写,因此找不到该列 (ORA -00904).

我想我通过扩展 SpringLiquibase 并添加我的自定义关键字找到了解决方法,如下所述:https://liquibase.jira.com/browse/CORE-3324. The problem is that this does not seem to work with OracleDatabase 实现,它覆盖了 SpringLiquibase 的一组保留关键字(当然,isReservedWord() 方法使用 OracleDatabase 的集合)。

现在,我将对 liquibase 和 hibernate.globally_quoted_identifiers 使用 QUOTE_ALL_OBJECTS 引用策略。

但是,出于好奇,我想知道是否可以附加 liquibase 用于 Oracle 的保留关键字集。

  • spring开机版本:2.3.9.RELEASE.
  • hibernate-core 版本(spring 启动依赖):5.4.28
  • liquibase-core 版本(spring 启动依赖):3.8.9

嗯,如果是 Oracle,你有关键字和保留字。

  • 保留字不能用作标识符
  • 关键字可以用作标识符,但不推荐使用。

您可以直接从数据库中获取它们的列表:

select KEYWORD, RESERVED from v$reserved_words;
...
1864 rows selected

在源代码中到处使用大写名称怎么样?

看起来 Liqubase 在功能上依赖于某些 JDBC 驱动程序 - 这是行不通的。

OracleDatabase.java:

public void setConnection(DatabaseConnection conn) {
    //noinspection HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,
    // HardCodedStringLiteral
    reservedWords.addAll(Arrays.asList("GROUP", "USER", "SESSION", "PASSWORD", "RESOURCE", "START", "SIZE", "UID", "DESC", "ORDER")); //more reserved words not returned by driver

    Connection sqlConn = null;
    if (!(conn instanceof OfflineConnection)) {
        try {
            /*
             * Don't try to call getWrappedConnection if the conn instance is
             * is not a JdbcConnection. This happens for OfflineConnection.
             * see https://liquibase.jira.com/browse/CORE-2192
             */
            if (conn instanceof JdbcConnection) {
                sqlConn = ((JdbcConnection) conn).getWrappedConnection();
            }
        } catch (Exception e) {
            throw new UnexpectedLiquibaseException(e);
        }

        if (sqlConn != null) {
            tryProxySession(conn.getURL(), sqlConn);

            try {
                //noinspection HardCodedStringLiteral
                reservedWords.addAll(Arrays.asList(sqlConn.getMetaData().getSQLKeywords().toUpperCase().split(",\s*")));
            } catch (SQLException e) {
                //noinspection HardCodedStringLiteral
                Scope.getCurrentScope().getLog(getClass()).info("Could get sql keywords on OracleDatabase: " + e.getMessage());
                //can not get keywords. Continue on
            }

如果 Liquibase 调用 sqlConn.getMetaData().getSQLKeywords() 而这没有 return 正确的输出,那么您的机会是有限的。这可能是 JDBC 驱动程序中的错误,或者您的应用程序没有 SELECT_CATALOG_ROLE 权限并且看不到 v$reserved_words 视图(如果 JDBC 在内部查询)。