私はpostgresqlデータベースとspring + hibernateフレームワークを使用してアプリケーションを書いています。
Springフレームワークを4.1.5.RELEASEから4.2.0.RELEASEバージョンにアップグレードし、hibernateフレームワークを4.3.7.Finalから5.0.0.Finalバージョンにアップグレードしました。
アップグレード後、NamingStrategyに問題があります。 postgresqlデータベースでは、テーブル列名はアンダースコアで区切られた小文字で、アプリケーション層では、Beanプロパティはキャメルケースです。
これは、古いバージョン用の機能するスプリング設定ファイルです。
<?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の改良されたNamingStrategyの代替手段を教えてください。また、実際の構成例を提供してください。
私は解決策を見つけたと思います。
目標を達成するために、hibernate.physical_naming_strategy
の代わりにhibernate.implicit_naming_strategy
構成を使用しました。
元の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 = "$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>
このソリューションが誰かに役立つことを願っています。 :)
<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>
私はまったく同じ問題を抱えていました。私はスプリングブートからのデフォルトの実装でそれを修正しました:
<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" />
Java Config Solutionをお探しの方へ
hibernate.ejb.naming_strategy
プロパティは、hibernate 5.Xでは2つの部分に分割されているようです。
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);
}
}
これを試して:
@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 {***
名前付け戦略の作業中に発見した3つのポイントを以下に示します。
アンダースコア付きの名前を持つエンティティークラスで_@Table
_および_@Column
_アノテーションを提供している場合、つまりuser_idつまり@Column(name="user_id")
、列名はuser_idとして取得されます。 useridとして指定すると、user_idに変わります戦略または暗黙的戦略を使用しない(具体的には_org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl
_)。したがって、エンティティ属性名がアンダースコアと小文字を含む名前に変更される戦略が必要な場合、つまりuserIdからuser_id、暗黙的またはまったく戦略を使用しないでください(実際には暗黙的戦略を使用します)。
命名戦略で列名またはクラス名にアンダースコアを追加したくない場合、使用する必要がある戦略は_spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
_のようになります。アノテーション_@Table
_および_@Column’s
_のname属性で提供するものはそのまま残ります。
注釈を提供せず、テーブル名と列名を手動で処理する場合は、クラス_org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
_を拡張し、必要なメソッドをオーバーライドする必要があります。ここでいくつかのケースで注釈を使用する場合は、オーバーライドされたメソッドがそれらの注釈で記述された名前に適用されることに注意してください。