oracle - 如何在 liquibase OracleDatabase 中添加保留关键字?
问题描述
试图使我的 Spring Boot JPA 应用程序与 Oracle DB 兼容,已经在 MySQL 和 H2 上运行。不幸的是,liquibase 生成的数据使用了一些 Oracle 的保留关键字作为表名或列名。
好消息是 hibernate 和 liquibase 实现可以检测这些关键字并在查询数据库时“引用”它们(objectQuotingStrategy="QUOTE_ONLY_RESERVED_KEYWORDS"
用于 liquibase 和spring.jpa.properties.hibernate.auto_quote_keyword: true
hibernate)。坏消息是 hibernate 和 liquibase 不共享相同的 Oracle 保留关键字列表。
例如, liquibase 不将value识别为保留关键字,但 hibernate(它使用 ANSI SQL:2003 关键字)将其识别为保留关键字。我的一个 liquibase changeSets 创建了一个带有小写值列的表,因此 Liquibase 创建了一个带有不带引号的小写值列的表,Oracle DB 自动将其转换为大写VALUE列。现在,当 hibernate 尝试获取该列时,它会识别value并将其引用(`SELECT "value" from ...),这使其区分大小写,因此找不到该列 (ORA-00904)。
我想我通过扩展 SpringLiquibase 并添加我的自定义关键字找到了解决方法,如下所述:https ://liquibase.jira.com/browse/CORE-3324 。问题是这似乎不适用于OracleDatabase实现,它覆盖了 SpringLiquibase 的保留关键字集(当然,该isReservedWord()
方法使用 OracleDatabase 的集)。
现在,我将使用QUOTE_ALL_OBJECTS
liquibase 和hibernate.globally_quoted_identifiers
.
但是,出于好奇,我想知道是否可以附加 liquibase 用于 Oracle 的保留关键字集。
- 春季启动版本:2.3.9.RELEASE。
- hibernate-core 版本(spring boot 依赖):5.4.28
- liquibase-core 版本(spring boot 依赖):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() 并且这没有返回正确的输出,那么你的机会是有限的。这可能是 JDBC 驱动程序中的错误,或者您的应用程序没有 SELECT_CATALOG_ROLE 权限并且看不到v$reserved_words
视图(如果 JDBC 在内部查询)。
推荐阅读
- javascript - 单击时不会弹出信息窗口
- css - 如何查看我的网站在哪里寻找 CSS 和媒体
- c# - `where T:Delegate` 还是`where T:MulticastDelegate`?
- listview - 如何在 xamarin 的列表视图中更改文本颜色
- python - 使用 HTTP POST 方法将图像从 raspberrypi (python) 发送到网络服务器后端 (php)
- reactjs - React-Admin is populating my
- with same element
- permissions - gitlab ci - 您无权访问该资源
- npm - 将 Angular 库发布到私有 Verdaccio npm 存储库
- c - C 比较速度:等于“==” vs Bitwise 和“&”
- php - 500 错误:使用 file_get_contents() 时,服务器配置中的 https:// 包装器被 allow_url_fopen=0 禁用