如何在 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 驱动程序 - 这是行不通的。
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 在内部查询)。
尝试使我的 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 驱动程序 - 这是行不通的。
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 在内部查询)。