Невозможно установить стратегию именования JPA после настройки нескольких источников данных (Spring 1.4.1/Hibernate 5.x)
Я использую Spring Boot 1.4.1, который использует Hibernate 5.0.11. Первоначально я настроил источник данных, используя application.properties
как это:
spring.datasource.uncle.url=jdbc:jtds:sqlserver://hostname:port/db
spring.datasource.uncle.username=user
spring.datasource.uncle.password=password
spring.datasource.uncle.dialect=org.hibernate.dialect.SQLServer2012Dialect
spring.datasource.uncle.driverClassName=net.sourceforge.jtds.jdbc.Driver
Я настроил его с помощью "дяди", потому что это будет имя одного из нескольких источников данных, которые я настроил. Я настроил этот источник данных, как это, согласно документам Spring:
@Bean
@Primary
@ConfigurationProperties(prefix = "spring.datasource.uncle")
public DataSource uncleDataSource() {
return DataSourceBuilder.create().build();
}
На данный момент все работает нормально.
Я создал класс @Entity
без каких- @Column
аннотаций @Column
и позволю Hibernate определить имена столбцов, например, если у меня есть свойство Java с именем idBank
, Hibernate автоматически примет имя столбца id_bank
. Это используется при генерации ddl, выполнении операторов SQL и т.д. Я хочу использовать эту функцию, потому что у меня будет много классов сущностей и вы не хотите создавать и поддерживать все аннотации @Column. На данный момент это сработало хорошо.
Затем я добавил еще один источник данных:
spring.datasource.aunt.url=jdbc:sybase:Tds:host2:port/db2
spring.datasource.aunt.username=user2
spring.datasource.aunt.password=password2
spring.datasource.aunt.dialect=org.hibernate.dialect.SybaseDialect
spring.datasource.aunt.driverClassName=com.sybase.jdbc4.jdbc.SybDriver
... а также это, следуя документам Spring для настройки нескольких источников данных. По-видимому, как только вы определяете второй источник данных, он не может настроить фасоли по умолчанию, и вы должны определить свой собственный EntityManager
и TransactionManager
. Поэтому в дополнение к источнику данных, сконфигурированному выше, я добавил следующие конфигурации:
@Bean
@Primary
PlatformTransactionManager uncleTransactionManager(@Qualifier("uncleEntityManagerFactory") final EntityManagerFactory factory) {
return new JpaTransactionManager(factory);
}
@Bean
@Primary
LocalContainerEntityManagerFactoryBean uncleEntityManagerFactory(
EntityManagerFactoryBuilder builder) {
return builder
.dataSource(uncleDataSource())
.packages(Uncle.class)
.persistenceUnit("uncle")
.build();
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.aunt")
public DataSource auntDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
PlatformTransactionManager auntTransactionManager(@Qualifier("auntEntityManagerFactory") final EntityManagerFactory factory) {
return new JpaTransactionManager(factory);
}
@Bean
LocalContainerEntityManagerFactoryBean auntEntityManagerFactory(
EntityManagerFactoryBuilder builder) {
return builder
.dataSource(auntDataSource())
.packages(Aunt.class)
.persistenceUnit("aunt")
.build();
}
Это работает с точки зрения подключения к базе данных и попыток получения данных.
ОДНАКО (и вот проблема, спасибо за то, что вы читаете это). После этих конфигураций я потерял подразумеваемую стратегию именования, которая переводит имена столбцов Java в имена змеиных змей, поэтому теперь, если у меня есть свойство Java idBank
он неправильно использует имя столбца idBank
вместо id_bank
. Мне бы очень хотелось вернуть эту функциональность.
Существует свойство JPA для этой spring.jpa.hibernate.naming-strategy
, и в Spring и Hibernate существуют различные классы стратегий именования, такие как org.springframework.boot.orm.jpa.hibernate.SpringNamingStrategy
. Поэтому я попытался настроить его так:
spring.jpa.hibernate.naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringNamingStrategy
Но это не сработало. Я пробовал некоторые варианты, такие как:
spring.datasource.uncle.naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringNamingStrategy
а также
spring.datasource.uncle.hibernate.naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringNamingStrategy
но это не имело никакого эффекта.
Затем я прочитал, что в Hibernate 5 стратегия именования была разбита на две части: "физическая" и "неявная", и для каждой из них есть разные настройки. Поэтому я попробовал это, с несколькими вариантами:
spring.jpa.hibernate.naming.physical-strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
а также
spring.jpa.hibernate.naming.implicit-strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
а также
spring.datasource.uncle.naming.physical-strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
а также
spring.datasource.uncle..hibernate.naming.implicit-strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
Но никто из них не работал.
Похоже, что мне нужно установить эту конфигурацию непосредственно в bean-компонентах, например, в SessionFactory
, но я не смог найти этот API. Документация вокруг этого, похоже, имеет некоторые пробелы.
Мне бы очень хотелось избежать установки persistence.xml
, который мне не нужен до этого момента.
Так вот, где я застрял, и я надеюсь, что кто-то может помочь. На самом деле, что бы я хотел, это способ отладки этих параметров свойств, я включил ведение журнала трассировки как в org.springframework
и в org.hibernate
но там ничего не было полезно. Я попытался выполнить код, когда эти компоненты были настроены, но не смог найти место, где это происходит. Если кто-то имеет эту информацию и может поделиться ею, я был бы очень благодарен.
Ответы
Ответ 1
У меня была та же проблема и исправлена ее с помощью следующего кода (адаптированного к коду в вопросе - для одного менеджера сущностей):
protected Map<String, Object> jpaProperties() {
Map<String, Object> props = new HashMap<>();
props.put("hibernate.physical_naming_strategy", SpringPhysicalNamingStrategy.class.getName());
props.put("hibernate.implicit_naming_strategy", SpringImplicitNamingStrategy.class.getName());
return props;
}
@Primary
@Bean(name = "defaultEntityManager")
public LocalContainerEntityManagerFactoryBean defaultEntityManagerFactory(
EntityManagerFactoryBuilder builder) {
return builder
.dataSource(auntDataSource())
.packages(Aunt.class)
.persistenceUnit("aunt")
.properties(jpaProperties())
.build();
}
Ответ 2
Если вы используете SessionFactory, вы должны использовать следующие строки, чтобы установить стратегии именования.
sessionFactory.setImplicitNamingStrategy(SpringImplicitNamingStrategy.INSTANCE);
sessionFactory.setPhysicalNamingStrategy(new SpringPhysicalNamingStrategy());
Ответ 3
То же, что и @ewert, можно получить, используя свойства:
# this works
spring.jpa.properties.hibernate.implicit_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
spring.jpa.properties.hibernate.physical_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
# but that does not work
spring.jpa.hibernate.naming.physical-strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
spring.jpa.hibernate.naming.implicit-strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
Ответ 4
Единственный способ, которым я правильно запустил это с Spring-Boot 2+, это установить вручную:
@Bean(name = "myEmf")
public LocalContainerEntityManagerFactoryBean sapEntityManagerFactory(
EntityManagerFactoryBuilder builder, @Qualifier("myDataSource") DataSource dataSource) {
return builder
.dataSource(dataSource)
.packages("my.custom.package")
.persistenceUnit("myPu")
.properties(getProperties())
.build();
}
public Map<String, String> getProperties() {
if (environment.getActiveProfiles().length == 1
&& environment.getActiveProfiles()[0].equals("test")) {
return Collections.singletonMap("hibernate.hbm2ddl.auto", "create");
}
return Collections.emptyMap();
}