java - Spring初始化多个数据库

标签 java database spring hibernate spring-boot

我正在使用 AbstractRoutingDatasource 在运行时在数据库之间进行路由。在 informix 数据库的真实情况下,一切都运行良好。

为了测试,我创建了一个 spring 配置文件以在内存 H2 数据库中使用。 在运行带有测试配置文件的 spring 应用程序后,我使用 h2 控制台检查了本地数据库。未创建架构。

我尝试在资源和 hibernate 中使用 schema.sql:

generate-ddl: true
hibernate:
  ddl-auto: create-drop

hibernate 抛出

java.lang.IllegalStateException: Cannot determine target DataSource for lookup key [null]

据我所知,hibernate ist 试图只生成“路由”数据源。由于没有设置 DatabaseContextHolder (null),因此失败。

所以这两种方式都失败了。

有没有办法用(相同的)模式初始化所有数据库?

我在下面列出了我的配置。

bootstrap.yml:

spring:
  profiles: acceptanceTest
  config:
    name: standalone
  cloud:
    config:
      enabled: false
      discovery:
        enabled: false
  jpa:
    database-platform: org.hibernate.dialect.H2Dialect
    generate-ddl: true
    hibernate:
      ddl-auto: create-drop
    properties:
      hibernate:
        show_sql: false
        use_sql_comments: false
        format_sql: false
  h2:
    console:
      enabled: true
      path: /h2
datasource:
  mc:
    driver-class-name: 'org.h2.Driver'
    url: 'jdbc:h2:mem:test-mc-db;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE'
    username: sa
    password: ''
    platform: h2
    initialize: true
    type: com.zaxxer.hikari.HikariDataSource
    hikari:
      maximum-pool-size: 10
      minimum-idle: 0
      idle-timeout: 60000
      pool-name: MarkHikariPool
  cw:
    driver-class-name: 'org.h2.Driver'
    url: 'jdbc:h2:mem:test-cw-db'
    username: sa
    password: ''
    type: com.zaxxer.hikari.HikariDataSource
    hikari:
      maximum-pool-size: 10
      minimum-idle: 0
      idle-timeout: 60000
      pool-name: MarkHikariPool

主应用程序.java:

@ComponentScan({ "de.md.mark" })
@EnableDiscoveryClient
@SpringBootApplication(
    exclude =
        {
            DataSourceAutoConfiguration.class,
            DataSourceTransactionManagerAutoConfiguration.class,
            HibernateJpaAutoConfiguration.class
        }
)
public class MainApp
{
    public static void main(String[] args)
    {

DataSourceConfiguration.java:

@Configuration
@EnableJpaRepositories(
    basePackageClasses = { MarkTypeRepository.class, MarkRepository.class }, entityManagerFactoryRef = "markEntityManager",
    transactionManagerRef = "markTransactionManager"
)
@EnableTransactionManagement
public class DataSourceConfiguration
{
    @Autowired(required = false)
    private PersistenceUnitManager persistenceUnitManager;

    @Bean
    @ConfigurationProperties("app.jpa")
    @Primary
    public JpaProperties jpaProperties()
    {
        return new JpaProperties();
    }

    @Bean
    @ConfigurationProperties(prefix = "datasource.mc")
    public DataSource mcDataSource()
    {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "datasource.cw")
    public DataSource cwDataSource()
    {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @Primary
    public DataSource dataSource()
    {
        DataSourceRouter router = new DataSourceRouter();

        final HashMap<Object, Object> map = new HashMap<>(DatabaseEnvironment.values().length);
        map.put(DatabaseEnvironment.MC, mcDataSource());
        map.put(DatabaseEnvironment.CW, cwDataSource());
        router.setTargetDataSources(map);
        return router;
    }

    @Bean
    @Primary
    public LocalContainerEntityManagerFactoryBean markEntityManager(final JpaProperties jpaProperties)
    {
        EntityManagerFactoryBuilder builder = createEntityManagerFactoryBuilder(jpaProperties);

        return builder.dataSource(dataSource()).packages(MarkTypeEntity.class).persistenceUnit("markEntityManager").build();
    }

    @Bean
    @Primary
    public JpaTransactionManager markTransactionManager(@Qualifier("markEntityManager") final EntityManagerFactory factory)
    {
        return new JpaTransactionManager(factory);
    }

    private EntityManagerFactoryBuilder createEntityManagerFactoryBuilder(JpaProperties jpaProperties)
    {
        JpaVendorAdapter jpaVendorAdapter = createJpaVendorAdapter(jpaProperties);
        return new EntityManagerFactoryBuilder(jpaVendorAdapter, jpaProperties.getProperties(), this.persistenceUnitManager);
    }

    private JpaVendorAdapter createJpaVendorAdapter(JpaProperties jpaProperties)
    {
        AbstractJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
        adapter.setShowSql(jpaProperties.isShowSql());
        adapter.setDatabase(jpaProperties.getDatabase());
        adapter.setDatabasePlatform(jpaProperties.getDatabasePlatform());
        adapter.setGenerateDdl(jpaProperties.isGenerateDdl());
        return adapter;
    }
}

最佳答案

经过过去两天的大量研究,我找到了一个初始化所有数据源的解决方案。 我创建了一个方法来使用 hibernate 的 SchemaExport.class 创建和初始化本地 H2 数据库。 因为我只需要本地数据库进行测试,所以我在 @Before cucumber 方法中为每个 DatabaseEnvirement 调用方法。

public void createDatabase(DatabaseEnvironment environment)
throws Exception
{
    // load hibernate configuration from hibernate.cfg.xml in classpath
    Configuration configuration = new Configuration().configure();
    MetadataSources metadata =
    new MetadataSources(new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build());

    ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(true);
    scanner.addIncludeFilter(new AnnotationTypeFilter(Entity.class));

    for (BeanDefinition def : scanner.findCandidateComponents(MarkEntity.class.getPackage().getName()))
    {
        metadata.addAnnotatedClass(Class.forName(def.getBeanClassName()));
    }

    Connection connection = DriverManager.getConnection("jdbc:h2:mem:test-" + environment.name().toLowerCase(), "sa", "");

    SchemaExport export = new SchemaExport((MetadataImplementor) metadata.buildMetadata(), connection);
    export.create(true, true);
}


@Before
public void beforeTest()
    throws Exception
{
    // initialise databases
    for (DatabaseEnvironment env : DatabaseEnvironment.values())
    {
        createDatabase(env);
    }
}

这就是我的 hibernate.cfg.xml 的样子:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
    <session-factory>

        <property name="dialect">org.hibernate.dialect.H2Dialect</property>

        <property name="show_sql">true</property>

        <property name="hbm2ddl.auto">create-drop</property>

    </session-factory>
</hibernate-configuration>

关于java - Spring初始化多个数据库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47138617/

相关文章:

database - 如何在 Windows 中使用的 Eclipse 中设置 Prolog Interpreter 路径?

database - 动态或列化的 tsvector 索引?

java - Spring +Redis+Mysql : cache strategy

java - 如何使用 Android 中的 MVP 模式从我的交互器启动服务?

java - servlet 仅显示数据库中的一项数据而不是全部

java - 如何找出是否在 Java 中从 catch block 调用了相同的方法?

mysql - 用于转储两个单独的 mysql 数据库并创建第三个数据库的脚本

java - 使用 Spring RMI 的 ClassNotFoundException

spring - 异常逻辑中的外部重定向在 Tomcat 8.5.39 上不起作用

java - 使用循环通过 JDBC 在 SQL 表中插入 1000 行 - 性能