Несколько источников данных весенней загрузки - PullRequest
0 голосов
/ 25 мая 2018

Я пытался буквально часов , чтобы заставить это работать, просматривая документы:

https://docs.spring.io/spring-boot/docs/current/reference/html/howto-data-access.html

... различные вопросы о переполнении стека и многое другоевещи, как я могу найти.Но это оказывается неуловимым (читай, заставляя меня хотеть ударить головой о стену).Любая помощь будет такой, так что добро пожаловать!

Мне нужно подключиться к двум разным базам данных (звучит достаточно просто?), И у меня есть веб-приложение Spring Boot, использующее зависимость spring-boot-starter-data-jpa, которая очень быстро начала работу.красиво с одним источником данных .Теперь мне нужно поговорить со второй базой данных, и все не работает.Я думал, что какое-то время это работало, но оказалось, что все идет в первичную базу данных.

В настоящее время я пытаюсь заставить это работать над отдельным «урезанным» проектом, чтобы попытаться уменьшитьколичество движущихся частей все еще не работает.

У меня есть два @Configuration класса - по одному для каждого источника данных, вот первый:

@Configuration
@EnableJpaRepositories(
        entityManagerFactoryRef = "firstEntityManagerFactory",
        transactionManagerRef = "firstTransactionManager",
        basePackages = {"mystuff.jpaexp.jpatest"})
public class DataConfiguration {
    @Bean
    @Primary
    @ConfigurationProperties(prefix = "app.datasource1")
    public DataSourceProperties firstDataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean
    @Primary
    @ConfigurationProperties("app.datasource1")
    public DataSource firstDataSource() {
        return firstDataSourceProperties().initializeDataSourceBuilder().
                driverClassName("org.postgresql.Driver").
                url("jdbc:postgresql://localhost:5432/experiment1").
                username("postgres").
                password("postgres").
                build();
    }

    @Primary
    @Bean
    public LocalContainerEntityManagerFactoryBean firstEntityManagerFactory() {
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setGenerateDdl(true);

        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setJpaVendorAdapter(vendorAdapter);
        factory.setPackagesToScan("mystuff.jpaexp.jpatest");
        factory.setDataSource(firstDataSource());
        factory.setPersistenceUnitName("ds1");
        return factory;
    }

    @Primary
    @Bean
    public PlatformTransactionManager firstTransactionManager() {
        return new JpaTransactionManager();
    }
}

и вот второй:

@Configuration
@EnableJpaRepositories(
        entityManagerFactoryRef = "secondEntityManagerFactory",
        transactionManagerRef = "secondTransactionManager",
        basePackages = {"mystuff.jpaexp.jpatest2"})
public class Otherconfiguration {
    @Bean
    @ConfigurationProperties(prefix = "app.datasource2")
    public DataSourceProperties secondDataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean
    @ConfigurationProperties("app.datasource2")
    public DataSource secondDataSource() {
        return secondDataSourceProperties().initializeDataSourceBuilder().
                driverClassName("org.postgresql.Driver").
                url("jdbc:postgresql://localhost:5432/experiment2").
                username("postgres").
                password("postgres").
                build();
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean secondEntityManagerFactory() {
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setGenerateDdl(true);

        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setJpaVendorAdapter(vendorAdapter);
        factory.setPackagesToScan("mystuff.jpaexp.jpatest2");
        factory.setDataSource(secondDataSource());
        factory.setPersistenceUnitName("ds2");
        return factory;
    }

    @Bean
    public PlatformTransactionManager secondTransactionManager() {
        return new JpaTransactionManager();
    }
}

В каждом из двух пакетов mystuff.jpaexp.jpatest и mystuff.jpaexp.jpatest2 у меня есть простые @Entity и CrudRepository, которые должны идти вместе с первым и вторым источниками данных соответственно.

Затем у меня есть main() для проверки:

@SpringBootApplication
@EnableAutoConfiguration(exclude = {WebMvcAutoConfiguration.class})
@ComponentScan("mystuff.jpaexp.*")
public class SpringbootCommandLineApp implements CommandLineRunner {
    private final MyRepository myRepository;
    private final OtherRepo otherRepo;

    @Autowired
    public SpringbootCommandLineApp(MyRepository myRepository, OtherRepo otherRepo) {
        this.myRepository = myRepository;
        this.otherRepo = otherRepo;
    }

    public static void main(String[] args) {
        new SpringApplicationBuilder(SpringbootCommandLineApp.class)
                .web(false)
                .run(args);
    }

    @Override
    public void run(String... args) throws Exception {
        myRepository.save(new MyEntity("Goodbye or hello"));
        myRepository.save(new MyEntity("What?"));
        myRepository.save(new MyEntity("1,2,3..."));

        myRepository.findAll().forEach(System.out::println);

        otherRepo.save(new MyEntity2("J Bloggs"));
        otherRepo.save(new MyEntity2("A Beecher"));
        otherRepo.save(new MyEntity2("C Jee"));

        otherRepo.findAll().forEach(x -> {
            System.out.println("Name:" + x.getName() + ", ID: " + x.getId());
        });
    }
}

И, наконец, некоторые реквизиты в application.properties:

app.datasource1.driver-class-name=org.postgresql.Driver
app.datasource1.url=jdbc:postgresql://localhost:5432/experiment1
app.datasource1.username=postgres
app.datasource1.password=postgres

app.datasource2.driver-class-name=org.postgresql.Driver
app.datasource2.url=jdbc:postgresql://localhost:5432/experiment2
app.datasource2.username=postgres
app.datasource2.password=postgres

Они не имеют абсолютно никакого эффекта - кажется, что все еще конфигурируется spring.datasource.*, что, очевидно, бесполезно.

Окончательный вывод:

2018-05-25 17:04:00.797  WARN 29755 --- [           main] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Tomcat.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.apache.tomcat.jdbc.pool.DataSource]: Factory method 'dataSource' threw exception; nested exception is org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Cannot determine embedded database driver class for database type NONE. If you want an embedded database please put a supported one on the classpath. If you have database settings to be loaded from a particular profile you may need to active it (no profiles are currently active).
2018-05-25 17:04:00.800  INFO 29755 --- [           main] utoConfigurationReportLoggingInitializer : 

Error starting ApplicationContext. To display the auto-configuration report re-run your application with 'debug' enabled.
2018-05-25 17:04:00.803 ERROR 29755 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

Cannot determine embedded database driver class for database type NONE

Action:

If you want an embedded database please put a supported one on the classpath. If you have database settings to be loaded from a particular profile you may need to active it (no profiles are currently active).


Process finished with exit code 1

Я знаю, что здесь много кода, извините испасибо!

1 Ответ

0 голосов
/ 30 мая 2018

Ну, это заняло много времени, я думаю, что было несколько тонких проблем, а также некоторые биты, которые можно было бы немного упростить:

  • Требовался только один DataSourceProperties - оба источника данных могут использоватьэто
  • @ConfigurationProperties необходимо в определении компонента DataSource, а не DataSourceProperties bean
  • I думаю, что аннотация @ComponentScan("mystuff.jpaexp.*") была неправильной, и заменила ее на* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 10 * * * * * * * * * * * * * * 10 * * * * * * * * * * * * * * * * * * * * * * * * * 10 * * * * * * * 10 * * * * * 10 * * * * 10 * * * 10 * * * 10 * * * 10 * * * * * * * * 10 * * * 10 * * "* bean, и explicity поместили эти свойства в VendorAdapter

Изменения VendorAdapter / JpaProperties выглядели так (кажется странным, что JpaProperties не зависит от производителя, но в нем есть hibernateProperties ?!):

@Bean
public LocalContainerEntityManagerFactoryBean secondEntityManagerFactory() {
    HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
    vendorAdapter.setGenerateDdl(true);

    LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
    factory.setJpaVendorAdapter(vendorAdapter);
    factory.setPackagesToScan("...entity-package...");
    factory.setDataSource(secondDataSource());
    Map<String, String> props = new HashMap<>();
    props.putAll(secondJpaProperties().getProperties());
    props.putAll(secondJpaProperties().getHibernateProperties(secondDataSource()));
    factory.setJpaPropertyMap(props);
    factory.setPersistenceUnitName("ds2");
    return factory;
}

@Bean
@ConfigurationProperties(prefix = "jpa.datsource2")
public JpaProperties secondJpaProperties() {
    return new JpaProperties();
}

Я думаю, этого было достаточно, чтобы все заработало.Кроме того, очень умные настройки по умолчанию различных свойств, заставляющие встроенный экземпляр H2 оживать, больше не работали, поэтому мне также пришлось четко указать все свойства DB:

jpa.datasource1.hibernate.ddl-auto=create
app.datasource1.driver-class-name=org.h2.Driver
app.datasource1.url=jdbc:h2:mem:primary
app.datasource1.username=
app.datasource1.password=

jpa.datasource2.hibernate.ddl-auto=create
app.datasource2.driver-class-name=org.h2.Driver
app.datasource2.url=jdbc:h2:mem:view
app.datasource2.username=
app.datasource2.password=
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...