[英]Set table name in Spring JPA
我想我正在嘗試做一些非常簡單的事情。 使用帶有 JPA 的 Spring Boot (1.3.3.RELEASE) 我想設置一個表名。
@Entity
@Table(name = "MyTable_name")
public class MyTableData {
...
}
我在我的數據庫中期望的是一個帶有“MyTable_name”的表。 對我來說似乎完全合理。 但這不會發生。 我得到一個名為“MY_TABLE_NAME”(H2 后端)或“my_table_name”(Postgre 后端)的表。 從這里開始,我將堅持使用 Postgre,因為我的目標是讀取我不控制表名的現有數據庫。
經過一些研究,我發現帖子說我應該使用 spring.jpa.hibernate.naming-strategy 屬性。 這沒有多大幫助。 設置為最常用的 org.hibernate.cfg.ImprovedNamingStrategy 會產生相同的行為:“my_table_name”。 設置為 org.hibernate.cfg.EJB3NamingStrategy 會生成“mytable_name”。 設置為 org.hibernate.cfg.DefaultNamingStrategy 會導致 Spring 內部的應用程序上下文錯誤。
我放棄了自己的編寫,開始查看 org.hibernate.cfg.ImprovedNamingStrategy。 我發現它使用了已棄用的 org.hibernate.cfg.NamingStrategy。 這建議改用 NamingStrategyDelegator。 我查看了它的Java 文檔,但不確定如何申請。 我找到了這個帖子。 盡管我很欣賞這個解釋,但在那里嘗試做的事情比我需要的要復雜得多,而且我在應用它時遇到了麻煩。
我的問題是如何讓 Spring JPA 只使用我指定的名稱? NamingStrategyDelegator 是否有新的屬性? 我需要編寫自己的策略嗎?
============ 更新 ==========================
我想我正在收斂於一個答案。 我創建了一個簡單的 Spring 啟動應用程序(與我的生產項目分開)。 我使用 H2 作為后端數據庫。
這個關於Hiberate 5 Naming 的討論非常有幫助。 有了它,我想出了如何在 Hibernate 5 中設置命名策略,如下所示(在 application.properties 中)。
hibernate.implicit_naming_strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl
hibernate.physical_naming_strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
我創建了一個通過名稱傳遞的物理命名策略(如 org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl 所做的那樣)並打印出值。 從中我看到表名是我想要的物理命名層。
然后我設置 hibernate.show_sql=true 來顯示生成 SQL。 在生成的 SQL 中,名稱也是正確的。
我正在使用 DatabaseMetaData 檢查表名。
private void showTables() throws SQLException {
DatabaseMetaData dbMetadata = getConnection().getMetaData();
ResultSet result = dbMetadata.getTables(null, null, null, new String[] { "TABLE" });
if (result != null) {
boolean haveTable = false;
while (result.next()) {
haveTable = true;
getLogger().info("Found table {}", result.getString("TABLE_NAME"));
}
if (!haveTable) {
getLogger().info("No tables found");
}
}
}
當我使用上面的代碼時,我仍然看到所有大寫的表名。 這讓我相信 DatabaseMetaData 出於某種原因顯示所有大寫,但其余代碼使用正確的名稱。 [編輯:這個結論是不正確的。 我只是對正在發生的一切感到困惑。 后來的測試顯示 DatabaseMetaData 顯示了大小寫正確的表名。]
這還不是一個完整的答案,因為我的生產代碼中仍有一些我需要調查的奇怪之處。 但它已經接近了,我想發布一個更新,這樣潛在的讀者就不會浪費時間。
這是我通過物理命名策略的過程,以防有人感興趣。 我知道看看其他人做了什么會有所幫助,尤其是在 Spring 迷宮中嘗試查找類和包時。
package my.domain.eric;
import java.io.Serializable;
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class NamingStrategyPhysicalLeaveAlone implements PhysicalNamingStrategy, Serializable {
private static final long serialVersionUID = -5937286882099274612L;
private static final Logger LOGGER = LoggerFactory.getLogger(NamingStrategyPhysicalLeaveAlone.class);
protected Logger getLogger() {
return LOGGER;
}
@Override
public Identifier toPhysicalCatalogName(Identifier name, JdbcEnvironment context) {
String nameText = name == null ? "" : name.getText();
getLogger().info("toPhysicalCatalogName name: {}", nameText);
return name;
}
@Override
public Identifier toPhysicalSchemaName(Identifier name, JdbcEnvironment context) {
String nameText = name == null ? "" : name.getText();
getLogger().info("toPhysicalSchemaName name: {}", nameText);
return name;
}
@Override
public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) {
String nameText = name == null ? "" : name.getText();
getLogger().info("toPhysicalTableName name: {}", nameText);
return name;
}
@Override
public Identifier toPhysicalSequenceName(Identifier name, JdbcEnvironment context) {
String nameText = name == null ? "" : name.getText();
getLogger().info("toPhysicalSequenceName name: {}", nameText);
return name;
}
@Override
public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment context) {
String nameText = name == null ? "" : name.getText();
getLogger().info("toPhysicalColumnName name: {}", nameText);
return name;
}
}
我的問題的答案涉及以下內容。
另一個令我感到困惑的原因是許多網站都引用了舊的命名變量hibernate.ejb.naming_strategy或它的彈簧等價物。 對於已經過時的Hibernate 5。 相反,正如我在我的問題更新中提到的,Hibernate 5具有隱式和物理命名策略。
此外,我很困惑,因為有hibernate屬性,然后有Spring屬性。 我正在使用這個非常有用的教程 。 然而,它顯示了不必要的直接使用hibernate屬性(我在我的更新中列出),然后顯式配置LocalContainerEntityManagerFactoryBean和JpaTransactionManager。 更容易使用Spring屬性並自動拾取它們。 與我相關的是命名策略。
要實現物理命名策略,我需要創建一個實現org.hibernate.boot.model.naming.PhysicalNamingStrategy的類,如上所述。 引用名稱實際上非常簡單,因為傳遞給方法的Identifier類管理或不管理引用。 因此,以下方法將引用表名。
@Override
public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) {
if (name == null) {
return null;
}
return Identifier.quote(name);
}
我學到的其他東西可能對來到這里尋找答案的人有所幫助。
該名稱在實體注釋中指定
@Entity(name = "MyTable_name")
public class MyTableData {
...
}
要將@Table(...)
指定的確切名稱作為數據庫中的表名,提出了以下解決方案:
application.yaml 文件
spring:
datasource:
url: jdbc:postgresql://localhost:5432/<dbname>?currentSchema=<schema-name>
username: <username>
password: <password>
jpa:
show-sql: true
hibernate:
# comment out ddl-auto as needed
ddl-auto: create-drop
naming:
# the following property is important for this topic:
# note that you are going implement the following java class:
physical-strategy: paul.tuhin.sbtutorial.NamingStrategy
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
default_schema: <schema-name>
format_sql: true
# this will quote your schema name as well:
globally_quoted_identifiers: true
paul.tuhin.sbtutorial.NamingStrategy.java 文件:
package paul.tuhin.sbtutorial;
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
public class NamingStrategy extends PhysicalNamingStrategyStandardImpl {
private static final long serialVersionUID = 1L;
@Override
public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) {
//The table name all converted to uppercase
String tableName = name.getText();
return Identifier.quote(Identifier.toIdentifier(tableName));
}
@Override
public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment context) {
String colnumName = name.getText();
return Identifier.quote(Identifier.toIdentifier(colnumName));
}
}
該解決方案改編自(感謝): https : //titanwolf.org/Network/Articles/Article?AID=b0f17470-3cfe-4ebc-9c45-25a462115be5
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.