spring-hibernate 5 命名策略配置
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32165694/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
spring - hibernate 5 naming strategy configuration
提问by Yoh0xFF
I am writing application using postgresql database and spring + hibernate frameworks.
我正在使用 postgresql 数据库和 spring + hibernate 框架编写应用程序。
I upgraded spring framework from 4.1.5.RELEASE to 4.2.0.RELEASE version and upgraded hibernate framework from 4.3.7.Final to 5.0.0.Final version.
我将 spring 框架从 4.1.5.RELEASE 升级到 4.2.0.RELEASE 版本,并将 hibernate 框架从 4.3.7.Final 升级到 5.0.0.Final 版本。
After upgrade I have problems with NamingStrategy. In postgresql database, table column names are in lowercase separated by underscore, in application layer, bean properties are in camelcase.
升级后,我遇到了 NamingStrategy 的问题。在postgresql数据库中,表列名用小写字母分隔,下划线分隔,在应用层,bean属性用驼峰命名。
This is working spring configuration file for older version:
这是旧版本的工作弹簧配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="fms" />
<bean id="microFmsDataSource" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close">
<property name="driverClassName" value="org.postgresql.Driver" />
<property name="url" value="***" />
<property name="username" value="***" />
<property name="password" value="***" />
<property name="testOnBorrow" value="true" />
<property name="testOnReturn" value="true" />
<property name="testWhileIdle" value="true" />
<property name="validationQuery" value="select 1" />
<property name="initialSize" value="5" />
<property name="minIdle" value="10" />
<property name="maxIdle" value="100" />
<property name="maxActive" value="100" />
<property name="removeAbandoned" value="true" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="microFmsDataSource"/>
<property name="packagesToScan">
<list>
<value>fms</value>
</list>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaPropertyMap">
<map>
<entry key="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider" />
<entry key="hibernate.hbm2ddl.auto" value="validate" />
<entry key="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
<entry key="hibernate.show_sql" value="true" />
<entry key="hibernate.format_sql" value="true" />
<entry key="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy" />
</map>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
After upgrade I changed NamingStrategy configuration:
升级后我更改了 NamingStrategy 配置:
<entry key="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy" />
like this:
像这样:
<entry key="hibernate.implicit_naming_strategy" value="***" />
and tried all variants of options listed in hibernate javadoc: https://docs.jboss.org/hibernate/orm/5.0/javadocs/org/hibernate/cfg/AvailableSettings.html#IMPLICIT_NAMING_STRATEGY
并尝试了 hibernate javadoc 中列出的所有选项变体:https: //docs.jboss.org/hibernate/orm/5.0/javadocs/org/hibernate/cfg/AvailableSettings.html#IMPLICIT_NAMING_STRATEGY
but with no success.
但没有成功。
Can you tell me what is alternative of ImprovedNamingStrategy in Hibernate 5 and provide a working configuration example ?
您能告诉我 Hibernate 5 中改进的NamingStrategy 的替代方案是什么,并提供一个有效的配置示例吗?
回答by Yoh0xFF
I think I found the solution.
我想我找到了解决方案。
To achieve my goal, I used hibernate.physical_naming_strategy
configuration, instead of hibernate.implicit_naming_strategy
.
为了实现我的目标,我使用了hibernate.physical_naming_strategy
配置,而不是hibernate.implicit_naming_strategy
.
I created an implementation of the PhysicalNamingStrategy
interface which simulates part of the functionality of the original ImprovedNamingStrategy
class:
我创建了一个PhysicalNamingStrategy
接口的实现,它模拟了原始ImprovedNamingStrategy
类的部分功能:
package fms.util.hibernate;
import org.apache.commons.lang.StringUtils;
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
public class ImprovedNamingStrategy implements PhysicalNamingStrategy {
@Override
public Identifier toPhysicalCatalogName(Identifier identifier, JdbcEnvironment jdbcEnv) {
return convert(identifier);
}
@Override
public Identifier toPhysicalColumnName(Identifier identifier, JdbcEnvironment jdbcEnv) {
return convert(identifier);
}
@Override
public Identifier toPhysicalSchemaName(Identifier identifier, JdbcEnvironment jdbcEnv) {
return convert(identifier);
}
@Override
public Identifier toPhysicalSequenceName(Identifier identifier, JdbcEnvironment jdbcEnv) {
return convert(identifier);
}
@Override
public Identifier toPhysicalTableName(Identifier identifier, JdbcEnvironment jdbcEnv) {
return convert(identifier);
}
private Identifier convert(Identifier identifier) {
if (identifier == null || StringUtils.isBlank(identifier.getText())) {
return identifier;
}
String regex = "([a-z])([A-Z])";
String replacement = "_";
String newName = identifier.getText().replaceAll(regex, replacement).toLowerCase();
return Identifier.toIdentifier(newName);
}
}
After I created this class, I changed my configuration from:
创建这个类后,我将配置从:
<entry key="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy" />
to this:
对此:
<entry key="hibernate.physical_naming_strategy" value="fms.util.hibernate.ImprovedNamingStrategy" />
and now everything works correctly.
现在一切正常。
This solution covers only small part of ImprovedNamingStrategy
. In my project, for table mapping and join mapping, I always specify the name of table or join column explicitly. I rely on implicit name conversion only for column names. So this simple solution was acceptable for me.
此解决方案仅涵盖ImprovedNamingStrategy
. 在我的项目中,对于表映射和联接映射,我总是明确指定表或联接列的名称。我只对列名依赖隐式名称转换。所以这个简单的解决方案对我来说是可以接受的。
This is a full example of my Spring configuration file:
这是我的 Spring 配置文件的完整示例:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="fms" />
<bean id="microFmsDataSource" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close">
<property name="driverClassName" value="org.postgresql.Driver" />
<property name="url" value="***" />
<property name="username" value="***" />
<property name="password" value="***" />
<property name="testOnBorrow" value="true" />
<property name="testOnReturn" value="true" />
<property name="testWhileIdle" value="true" />
<property name="validationQuery" value="select 1" />
<property name="initialSize" value="5" />
<property name="minIdle" value="10" />
<property name="maxIdle" value="100" />
<property name="maxActive" value="100" />
<property name="removeAbandoned" value="true" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="microFmsDataSource"/>
<property name="packagesToScan">
<list>
<value>fms</value>
</list>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaPropertyMap">
<map>
<entry key="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider" />
<entry key="hibernate.hbm2ddl.auto" value="validate" />
<entry key="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
<entry key="hibernate.show_sql" value="true" />
<entry key="hibernate.format_sql" value="true" />
<entry key="hibernate.physical_naming_strategy" value="fms.util.hibernate.ImprovedNamingStrategy" />
</map>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
I hope this solution will be helpful for somebody. :)
我希望这个解决方案对某人有帮助。:)
回答by Manish Kothari
For anyone looking for a Java Config Solution
对于任何寻找 Java 配置解决方案的人
The hibernate.ejb.naming_strategy
property seems split into two parts in hibernate 5.X:
该hibernate.ejb.naming_strategy
属性在 hibernate 5.X 中似乎分为两部分:
hibernate.physical_naming_strategy
hibernate.physical_naming_strategy
hibernate.implicit_naming_strategy
hibernate.implicit_naming_strategy
Spring provides SpringImplicitNamingStrategy
and SpringPhysicalNamingStrategy
for this purpose.
Spring 提供SpringImplicitNamingStrategy
并SpringPhysicalNamingStrategy
为此目的。
Here is my approach:
这是我的方法:
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy;
import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@DependsOn("myDataSource")
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "myEntityManagerFactory",
basePackages={"com.myapp.repo"},
transactionManagerRef="myTransactionManager"
)
public class MyJpaConfig {
private Map<String, Object> properties;
public MyJpaConfig() {
properties = new HashMap<>();
properties.put("hibernate.implicit_naming_strategy", SpringImplicitNamingStrategy.class.getName());
properties.put("hibernate.physical_naming_strategy", SpringPhysicalNamingStrategy.class.getName());
}
@Bean(name = "myEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder,
@Qualifier("systemDataSource") DataSource dataSource) {
LocalContainerEntityManagerFactoryBean build = builder.dataSource(dataSource)
.packages("com.myapp.entity")
.properties(properties)
.build();
return build;
}
@Bean(name = "myTransactionManager")
public PlatformTransactionManager myTransactionManager(
@Qualifier("myEntityManagerFactory") EntityManagerFactory myEntityManagerFactory) {
return new JpaTransactionManager(myEntityManagerFactory);
}
}
回答by JSimo
I had the exactly same problem. I fixed it with default implementation from spring boot:
我遇到了完全相同的问题。我用 spring boot 的默认实现修复了它:
<property name="hibernate.implicit_naming_strategy" value="org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy" />
<property name="hibernate.physical_naming_strategy" value="org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy" />
回答by Daniel Qian
This work for me, from http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/orm/hibernate5/LocalSessionFactoryBean.html
这对我有用,来自http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/orm/hibernate5/LocalSessionFactoryBean.html
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<!-- convert aaBb to aa_bb -->
<property name="PhysicalNamingStrategy">
<bean class="fms.util.hibernate.ImprovedNamingStrategy" />
</property>
<!-- convert aa_bb to aaBb -->
<property name="ImplicitNamingStrategy">
<bean class="org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl" />
</property>
...
</bean>
回答by helloworld1970
try this:
尝试这个:
@Bean
public LocalSessionFactoryBean getSessionFactory() {
LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();
localSessionFactoryBean.setDataSource(getDataSource());
localSessionFactoryBean.setHibernateProperties(getHibernateProperties());
localSessionFactoryBean.setPackagesToScan(new String[]{"com.xxx.pojo"});
// -----important-----
localSessionFactoryBean.setPhysicalNamingStrategy(new CustomNamingStrategy());
return localSessionFactoryBean;
}
public class CustomNamingStrategy extends PhysicalNamingStrategyStandardImpl {***
回答by Raj Kundalia
Please find below 3 points that I discovered while working on Naming Strategy:
请找出我在研究命名策略时发现的以下 3 点:
If you are providing
@Table
and@Column
annotation in your entity classes with names provided with an underscore i.e. user_idi.e.@Column(name="user_id")
, it will take the column name as user_id; if you give it as useridthen it will change to user_idif you use no strategy or implicit strategy (specificallyorg.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl
). So, if you want a strategy where the entity attribute name changes to one with underscore and lowercase letters i.e. something from userIdto user_id, you should use implicit or no strategy (which actually uses implicit strategy).If you don't want your naming strategy to add an underscore to the column name or class name, then the strategy that you need to use would look like:
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
. The things that you provide in annotations@Table
and@Column's
name attribute would remain as it is.If you don't want to provide annotations and want to manually handle the table name and column names, you should extend the class
org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
and override the required methods. If you still use annotations for some of the cases here, remember the overridden methods will apply on the names written in those annotations.
如果您在实体类中提供
@Table
和@Column
注释的名称带有下划线,即user_idie@Column(name="user_id")
,它将采用列名作为user_id;如果您将其作为userid 提供,那么如果您不使用策略或隐式策略(特别是),它将更改为user_idorg.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl
。因此,如果您想要一种策略,其中实体属性名称更改为带有下划线和小写字母的名称,即从userId到user_id 的内容,您应该使用隐式或不使用策略(实际上使用隐式策略)。如果您不希望命名策略为列名或类名添加下划线,那么您需要使用的策略如下:
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
. 您在注释@Table
和@Column's
名称属性中提供的内容将保持原样。如果不想提供注解而想手动处理表名和列名,则应扩展该类
org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
并覆盖所需的方法。如果您仍然在此处的某些情况下使用注释,请记住重写的方法将应用于这些注释中写入的名称。