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

gojuced7  于 2023-11-21  发布在  Spring
关注(0)|答案(6)|浏览(104)

我使用的是Sping 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

字符串
我用“uncle”配置它,因为这将是我将要配置的多个数据源之一的名称。根据Spring文档,我这样配置了这个数据源:

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


在这一点上,一切都很好。
我创建了一个没有任何@Column注解的@Entity类,并让Hibernate确定列名,例如,如果我有一个名为idBank的Java属性,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。我真的很想恢复那个功能。

这个spring.jpa.hibernate.naming-strategy有一个JPA属性,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时,我尝试单步执行代码,但无法找到发生这种情况的位置。如果有人有这些信息并可以分享,我会真的很感激。

blmhpbnm

blmhpbnm1#

我遇到了同样的问题,并使用以下代码修复了它(适用于问题中的代码-用于单个实体管理器):

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();
}

字符串

balp4ylt

balp4ylt2#

与@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 doesn't 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

字符串

9wbgstp7

9wbgstp73#

我想我可以解释为什么默认行为消失,根据你的最新问题。
从Sping Boot 2.4.2开始,在JpaBaseConfiguration的这个方法中开始使用配置:

@Bean
    @Primary
    @ConditionalOnMissingBean({ LocalContainerEntityManagerFactoryBean.class, EntityManagerFactory.class })
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder factoryBuilder) {
        Map<String, Object> vendorProperties = getVendorProperties();
        customizeVendorProperties(vendorProperties);
        return factoryBuilder.dataSource(this.dataSource).packages(getPackagesToScan()).properties(vendorProperties)
                .mappingResources(getMappingResources()).jta(isJta()).build();
    }

字符串
它发生在customizeVendorProperties方法调用中。
通过创建您自己的LocalContainerEntityManagerFactoryBean bean(实际上是两个),这种定制不再执行。

7d7tgy0s

7d7tgy0s4#

如果你使用的是SessionFactory,你应该使用下面的行来设置命名策略。

sessionFactory.setImplicitNamingStrategy(SpringImplicitNamingStrategy.INSTANCE);
sessionFactory.setPhysicalNamingStrategy(new SpringPhysicalNamingStrategy());

字符串

eoigrqb6

eoigrqb65#

充值上@ewert回答:

Spring Boot3.1.5

不赞成使用SpringPhysicalNamingStrategy,请改用CamelCaseToUnderscoresNamingStrategy
github的一个。

props.put("hibernate.physical_naming_strategy", CamelCaseToUnderscoresNamingStrategy.class.getName());
props.put("hibernate.implicit_naming_strategy", SpringImplicitNamingStrategy.class.getName());

字符串

gstyhher

gstyhher6#

我使用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() {
   val props = new HashMap<String, String>();

    if (isTest()) {
      props.put("hibernate.hbm2ddl.auto", "create");
    } else {
      props.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQL95Dialect");
    }
    return props;
  }

字符串

相关问题