小编典典

配置多个数据源后无法设置JPA命名策略(Spring 1.4.1 / Hibernate 5.x)

spring-boot

我正在使用使用Hibernate 5.0.11的Spring Boot
1.4.1。最初,我使用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

我将其配置为“ uncle”,因为这将是我将配置的多个数据源之一的名称。根据Spring文档,我像这样配置了此数据源:

@Bean
@Primary
@ConfigurationProperties(prefix = "spring.datasource.uncle")
public DataSource uncleDataSource() {
    return DataSourceBuilder.create().build();
}

此时一切正常。

我创建了一个@Entity没有任何@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文档设置多个数据源的方法。显然,一旦定义了第二个数据源,它就无法配置默认Bean,而您必须定义自己的EntityManagerTransactionManager。因此,除了上面配置的数据源之外,我还添加了以下配置:

@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.springframeworkorg.hibernate但是那里没有任何用处。在配置这些bean时,我尝试单步执行代码,但是找不到发生这种情况的位置。如果有人拥有该信息并可以分享,我将非常感激。


阅读 865

收藏
2020-05-30

共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();
}
2020-05-30