Spring 使用多个数据源时启动 Hibernate 错误 "Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set"

Spring boot Hibernate error "Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set" when working with multiple data sources

我正在构建一个 Spring 启动应用程序,它需要与 2 个不同的数据库(DB2 和 Oracle)通信。

Spring-boot-starter-parent 版本 2.6.6

休眠版本 5.6.7.Final

我首先添加了 DB2 支持并且在我在下面的 application.properties 文件中添加 oracle 相关设置之前工作正常。

添加oracle相关设置导致以下错误:

org.hibernate.HibernateException:当'hibernate.dialect'未设置

时,对DialectResolutionInfo的访问不能为空

以下是我的 application.properties:

中的数据库和休眠相关设置
# ==============================
# = DB2 
db2.datasource.jdbc-url=jdbc:db2://SERVER1:PORT/DATABASE-1:currentSchema=SCHEMA;
db2.datasource.username=USER1
db2.datasource.password=PASSWORD1
db2.datasource.driver-class-name=com.ibm.db2.jcc.DB2Driver
db2.jpa.properties.hibernate.dialect=org.hibernate.dialect.DB2390Dialect

# ==============================
# = ORACLE
oracle.datasource.jdbc-url=jdbc:oracle:thin:@SERVER2:PORT/DATABASE-2
oracle.datasource.username=USER2
oracle.datasource.password=PASSWORD2
oracle.jpa.properties.hibernate.dialect=org.hibernate.dialect.Oracle10gDialect

# ==============================
# = JPA / HIBERNATE
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

我的 pom.xml 包含 oracle 和 DB2 的依赖项以及其他必需的依赖项:

... 
<dependency>
        <groupId>com.ibm.db2</groupId>
        <artifactId>jcc</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>com.oracle.database.jdbc</groupId>
        <artifactId>ojdbc8</artifactId>
        <scope>runtime</scope>
    </dependency>
...

我已将我的实体、存储库和数据源配置放入不同的包中,因为我在本文 https://www.javadevjournal.com/spring-boot/multiple-data-sources-with-spring-boot/ 中看到了要求。我的包结构如下:

project
  - dataconfig
      - db2
        - config
        - entity
        - repository
      - oracle
        - config
        - entity
        - repository

我还添加了一些实体和存储库以及我的配置 classes.

这是我的 DB2Configuration class:

package project.dataconfig.db2.config;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "db2EntityManagerFactory",
        transactionManagerRef = "db2TransactionManager",
        basePackages = {
                "project.dataconfig.db2.repository"
        }
)
public class Db2Configuration {

    @Primary
    @Bean(name = "db2DataSource")
    @ConfigurationProperties(prefix = "db2.datasource")
    public DataSource db2DataSource() {

        return DataSourceBuilder.create().build();
    }

    @Primary
    @Bean(name = "db2EntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(
            EntityManagerFactoryBuilder builder
            , @Qualifier("db2DataSource") DataSource dataSource) {

        return builder
                .dataSource(dataSource)
                .packages("project.dataconfig.db2.entity")
                .persistenceUnit("db2persistanceunit")
                .build();
    }

    @Primary
    @Bean(name = "db2TransactionManager")
    public PlatformTransactionManager db2TransactionManager(
      @Qualifier("db2EntityManagerFactory") EntityManagerFactory db2EntityManagerFactory) {

        return new JpaTransactionManager(db2EntityManagerFactory);
    }
}

这是我的 OracleConfiguration class:

package project.dataconfig.oracle.config;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "oracleEntityManagerFactory",
        transactionManagerRef = "oracleTransactionManager",
        basePackages = {
                "project.dataconfig.oracle.repository"
        }
)
public class OracleConfiguration {

        @Bean(name = "oracleDataSource")
        @ConfigurationProperties(prefix = "oracle.datasource")
        public DataSource oracleDataSource() {

                return DataSourceBuilder.create().build();
        }

        @Bean(name = "oracleEntityManagerFactory")
        public LocalContainerEntityManagerFactoryBean entityManagerFactory(
                EntityManagerFactoryBuilder builder
                , @Qualifier("oracleDataSource") DataSource dataSource) {

                return builder
                        .dataSource(dataSource)
                        .packages("project.dataconfig.oracle.entity")
                        .persistenceUnit("oraclepersistanceunit")
                        .build();
        }

        @Bean(name = "oracleTransactionManager")
        public PlatformTransactionManager oracleTransactionManager(
                @Qualifier("oracleEntityManagerFactory") EntityManagerFactory oracleEntityManagerFactory) {

                return new JpaTransactionManager(oracleEntityManagerFactory);
        }
}

在我在 application.properties 文件中添加 oracle 相关设置之前,我的应用程序只使用如上所述的 DB2 设置进行查找。

添加 oracle 相关设置和配置后,我开始收到此错误:

org.hibernate.HibernateException:当'hibernate.dialect'未设置

时,对DialectResolutionInfo的访问不能为空

根据错误,我认为问题是由我在 application.properties 文件中对 Hibernate 方言的设置引起的。我认为这是由两个设置之一引起的

...
db2.jpa.properties.hibernate.dialect=org.hibernate.dialect.DB2390Dialect

...
oracle.jpa.properties.hibernate.dialect=org.hibernate.dialect.Oracle10gDialect

如何解决这个问题?

我想出来了。

修改 Db2ConfigurationOracleConfiguration 的方法 entityManagerFactory 以向它们提供有关休眠方言的信息:

对于 DB2

@Primary
@Bean(name = "db2EntityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
        EntityManagerFactoryBuilder builder
        , @Qualifier("db2DataSource") DataSource dataSource) {

    final HashMap<String, Object> hibernateProperties = new HashMap<String, Object>();
    hibernateProperties.put("hibernate.dialect", "org.hibernate.dialect.DB2390Dialect");

    return builder
            .dataSource(dataSource)
            .packages("project.dataconfig.db2.entity")
            .properties(hibernateProperties)
            .persistenceUnit("db2persistanceunit")
            .build();
}

对于 Oracle

@Bean(name = "oracleEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
        EntityManagerFactoryBuilder builder
        , @Qualifier("oracleDataSource") DataSource dataSource) {

    final HashMap<String, Object> hibernateProperties = new HashMap<String, Object>();
    hibernateProperties.put("hibernate.dialect", "org.hibernate.dialect.Oracle10gDialect");

    return builder
            .dataSource(dataSource)
            .packages("project.dataconfig.oracle.entity")
            .properties(hibernateProperties)
            .persistenceUnit("oraclepersistanceunit")
            .build();
}

之后,我的控制台显示 运行 app,表明一切正常:

HHH000400: Using dialect: org.hibernate.dialect.DB2390Dialect
 Initialized JPA EntityManagerFactory for persistence unit 'db2persistanceunit'
HHH000204: Processing PersistenceUnitInfo [name: oraclepersistanceunit]
HHH000400: Using dialect: org.hibernate.dialect.Oracle10gDialect
Initialized JPA EntityManagerFactory for persistence unit 'oraclepersistanceunit'

我的执行器 /health 端点也看到两个数据库都已启动并且 运行。