복붙노트

[SPRING] 봄 - 최대 절전 모드 5 명명 전략 구성

SPRING

봄 - 최대 절전 모드 5 명명 전략 구성

postgresql 데이터베이스와 봄 + 최대 절전 모드 프레임 워크를 사용하여 응용 프로그램을 작성하고 있습니다.

4.1.5.RELEASE에서 4.2.0.RELEASE 버전으로 스프링 프레임 워크를 업그레이드하고 4.3.7에서 최종 절전 프레임 워크를 5.0.0으로 업그레이드했습니다. 최종 버전.

업그레이드가 끝나면 NamingStrategy에 문제가 있습니다. postgresql 데이터베이스에서 테이블 열 이름은 밑줄로 구분하여 소문자로 표시되며, 응용 프로그램 계층에서는 bean 속성이 camelcase에 있습니다.

이전 버전의 스프링 구성 파일입니다.

<?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>

업그레이드 후 NamingStrategy 구성이 변경되었습니다.

<entry key="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy" />

이렇게 :

<entry key="hibernate.implicit_naming_strategy" value="***" />

hibernate javadoc에 나열된 모든 변형을 시험해 보았다 : https://docs.jboss.org/hibernate/orm/5.0/javadocs/org/hibernate/cfg/AvailableSettings.html#IMPLICIT_NAMING_STRATEGY

그러나 성공하지 못했습니다.

당신은 Hibernate 5에서 ImprovedNamingStrategy의 대안이 무엇인지 말해 줄 수 있습니까? 그리고 작동하는 설정 예제를 제공합니까?

해결법

  1. ==============================

    1.솔루션을 찾은 것 같습니다.

    솔루션을 찾은 것 같습니다.

    내 목표를 달성하기 위해 hibernate.implicit_naming_strategy 대신 hibernate.physical_naming_strategy 구성을 사용했습니다.

    필자는 원래 ImprovedNamingStrategy 클래스의 기능 중 일부를 시뮬레이트하는 PhysicalNamingStrategy 인터페이스의 구현을 만들었습니다.

    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 = "$1_$2";
            String newName = identifier.getText().replaceAll(regex, replacement).toLowerCase();
            return Identifier.toIdentifier(newName);
        }
    }
    

    이 클래스를 만든 후에 구성을 다음으로 변경했습니다.

    <entry key="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy" />
    

    이에:

    <entry key="hibernate.physical_naming_strategy" value="fms.util.hibernate.ImprovedNamingStrategy" />
    

    이제 모든 것이 올바르게 작동합니다.

    이 솔루션은 ImprovedNamingStrategy의 작은 부분만을 다룹니다. 내 프로젝트에서 테이블 매핑 및 조인 매핑을 위해 항상 테이블의 이름을 지정하거나 명시 적으로 열을 조인합니다. 필자는 열 이름에 대해서만 암시 적 이름 변환을 사용합니다. 그래서이 간단한 해결책은 나에게 받아 들일 만했다.

    다음은 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>
    

    이 솔루션이 누군가에게 도움이되기를 바랍니다. :)

  2. ==============================

    2.이 작품은 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>   
    
  3. ==============================

    3.Java Config Solution을 원하는 누구나

    Java Config Solution을 원하는 누구나

    hibernate.ejb.naming_strategy 속성은 Hibernate 5.X에서 두 부분으로 나뉘어 보인다.

    hibernate.physical_naming_strategy

    hibernate.implicit_naming_strategy

    Spring은이를 위해 SpringImplicitNamingStrategy와 SpringPhysicalNamingStrategy를 제공한다.

    여기 내 접근 방식입니다 :

    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);
        }
    }
    
  4. ==============================

    4.나는 똑같은 문제가 있었다. 스프링 부트에서 기본 구현으로 수정했습니다.

    나는 똑같은 문제가 있었다. 스프링 부트에서 기본 구현으로 수정했습니다.

    <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" />
    
  5. ==============================

    5.이 시도:

    이 시도:

    @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 {***
    
  6. ==============================

    6.나에게 맞는 풀 스프링 설정 :

    나에게 맞는 풀 스프링 설정 :

        <property name="dataSource" ref="dataSource"/>
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="database" value="${db.platform}"/>
                <property name="generateDdl" value="false"/>
            </bean>
        </property>
        <property name="jpaProperties">
            <props>
                <!--<prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>-->
                <prop key="hibernate.implicit_naming_strategy">org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl</prop>
                <prop key="hibernate.format_sql">${hibernate.format_sql:false}</prop>
                <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto:validate}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql:false}</prop>
                <prop key="hibernate.use_sql_comments">${hibernate.use_sql_comments:false}</prop>
                <prop key="hibernate.id.new_generator_mappings">${hibernate.id.new_generator_mappings:true}</prop>
                <prop key="hibernate.enable_lazy_load_no_trans">${hibernate.enable_lazy_load_no_trans:true}</prop>
                <prop key="hibernate.max_fetch_depth">${hibernate.max_fetch_depth:1}</prop>
                <prop key="hibernate.default_batch_fetch_size">${hibernate.default_batch_fetch_size:16}</prop>
            </props>
        </property>
    </bean>
    
  7. from https://stackoverflow.com/questions/32165694/spring-hibernate-5-naming-strategy-configuration by cc-by-sa and MIT license