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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 00:45:02  来源:igfitidea点击:

spring - hibernate 5 naming strategy configuration

springconfigurationhibernate-5.x

提问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_strategyconfiguration, instead of hibernate.implicit_naming_strategy.

为了实现我的目标,我使用了hibernate.physical_naming_strategy配置,而不是hibernate.implicit_naming_strategy.

I created an implementation of the PhysicalNamingStrategyinterface which simulates part of the functionality of the original ImprovedNamingStrategyclass:

我创建了一个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_strategyproperty 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 SpringImplicitNamingStrategyand SpringPhysicalNamingStrategyfor this purpose.

Spring 提供SpringImplicitNamingStrategySpringPhysicalNamingStrategy为此目的。

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 点:

  1. If you are providing @Tableand @Columnannotation 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 (specifically org.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).

  2. 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 @Tableand @Column'sname attribute would remain as it is.

  3. 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.PhysicalNamingStrategyStandardImpland 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.

  1. 如果您在实体类中提供@Table@Column注释的名称带有下划线,即user_idie @Column(name="user_id"),它将采用列名作为user_id;如果您将其作为userid 提供,那么如果您不使用策略或隐式策略(特别是),它将更改为user_idorg.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl。因此,如果您想要一种策略,其中实体属性名称更改为带有下划线和小写字母的名称,即从userIduser_id 的内容,您应该使用隐式或不使用策略(实际上使用隐式策略)。

  2. 如果您不希望命名策略为列名或类名添加下划线,那么您需要使用的策略如下: spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl. 您在注释@Table@Column's名称属性中提供的内容将保持原样。

  3. 如果不想提供注解而想手动处理表名和列名,则应扩展该类org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl并覆盖所需的方法。如果您仍然在此处的某些情况下使用注释,请记住重写的方法将应用于这些注释中写入的名称。