1

I have spent some days trying to solve this error but without success. I am trying to configure two databases and write in both of them.

I looked at:

https://medium.com/@joeclever/using-multiple-datasources-with-spring-boot-and-spring-data-6430b00c02e7

https://www.baeldung.com/spring-data-jpa-multiple-databases

https://www.devglan.com/spring-boot/spring-boot-multiple-database-configuration

https://raymondhlee.wordpress.com/2015/10/31/configuring-multiple-jpa-entity-managers-in-spring-boot/

https://github.com/igormukhin/spring-boot-sample-data-jpa-multiple/blob/master/src/main/java/sample/data/jpa/Database1Configuration.java And a loot more links from SO for the errors or similar examples.

Here is my code:

fromDB.datasource.url=jdbc:h2:file:D:/test1/db1
fromDB.datasource.username=sa
fromDB.datasource.password=
fromDB.datasource.platform=h2
fromDB.datasource.driverClassName=org.h2.Driver

toDB.datasource.url=jdbc:h2:file:D:/test2/db2
toDB.datasource.username=sa
toDB.datasource.password=
toDB.datasource.platform=h2
toDB.datasource.driverClassName=org.h2.Driver

spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
spring.h2.console.settings.trace=true
spring.h2.console.settings.web-allow-others=true
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

Hibernate Settings -hibernate.properties

spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.use_sql_comments=false
spring.jpa.properties.hibernate.format_sql=true
spring.datasource.initialization-mode=always
spring.datasource.initialize=true
spring.jpa.generate-ddl=true

ConfigClasses

    @Configuration
    @EnableTransactionManagement
    @EnableJpaRepositories(
        entityManagerFactoryRef = "toEntityManager",
        transactionManagerRef = "toTransactionManager",
        basePackages = "leadTime.service"
    )
    public class ToDBConfig {

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

      @Bean(name = "toEntityManager")
      public LocalContainerEntityManagerFactoryBean toEntityManagerFactory(
          EntityManagerFactoryBuilder builder) {
        return builder
            .dataSource(toDataSource())
            .properties(hibernateProperties())
            .packages(TestDataTo.class)
            .persistenceUnit("to")
            .build();
      }

      @Bean(name = "toTransactionManager")
      public PlatformTransactionManager toTransactionManager(@Qualifier("toEntityManager") EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
      }

      private Map hibernateProperties() {

        Resource resource = new ClassPathResource("hibernate.properties");

        try {
          Properties properties = PropertiesLoaderUtils.loadProperties(resource);

          return properties.entrySet().stream()
              .collect(Collectors.toMap(
                  e -> e.getKey().toString(),
                  e -> e.getValue())
              );
        } catch (IOException e) {
          return new HashMap();
        }
      }
    }

Second configClass

    @Configuration
    @EnableTransactionManagement
    @EnableJpaRepositories(
        entityManagerFactoryRef = "fromEntityManager",
        transactionManagerRef = "fromTransactionManager",
        basePackages = "leadTime.service"
    )
    public class FromDBConfig {

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

      @Primary
      @Bean(name = "fromEntityManager")
      public LocalContainerEntityManagerFactoryBean fromEntityManagerFactory(
          EntityManagerFactoryBuilder builder) {
        return builder
            .dataSource(fromDataSource())
            .properties(hibernateProperties())
            .packages(TestDataFrom.class)
            .persistenceUnit("from")
            .build();
      }

      @Primary
      @Bean(name = "fromTransactionManager")
      public PlatformTransactionManager fromTransactionManager(@Qualifier("fromEntityManager") EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
      }

      private Map hibernateProperties() {

        Resource resource = new ClassPathResource("hibernate.properties");

        try {
          Properties properties = PropertiesLoaderUtils.loadProperties(resource);

          return properties.entrySet().stream()
              .collect(Collectors.toMap(
                  e -> e.getKey().toString(),
                  e -> e.getValue())
              );
        } catch (IOException e) {
          return new HashMap();
        }
      }}

Repository:

    public interface ToRepository extends CrudRepository<TestDataTo, Integer> 
    {

      @Override
      TestDataTo save(TestDataTo testDataTo);
    }

DataInit:

    @Component
    public class DataInit {
      @Autowired
      ToRepository toRepository;

      @Autowired
      FromRepository fromRepository;

      @Transactional("fromTransactionManager")
      public void insertDataIntoFromDB() throws SQLException {
        TestDataFrom testDataFrom = new TestDataFrom();
        testDataFrom.setId(1);
        testDataFrom.setName("Test");
        fromRepository.save(testDataFrom);

      }
      //
      @Transactional("toTransactionManager")
      public void insertDataIntoToDB() throws SQLException {

        TestDataTo testDataTo = new TestDataTo();
        testDataTo.setId(1);
        testDataTo.setName("Ale");
        toRepository.save(testDataTo);
      }
    }

MainClass:

    @EnableTransactionManagement
    @SpringBootApplication
    public class LeadTimeApplication  {
      private Logger LOG = LoggerFactory.getLogger("LeadTimeApplication");

      @Autowired
      ToRepository toRepository;

      @Autowired
      FromRepository fromRepository;

      public static void main(String[] args) {
        SpringApplication.run(LeadTimeApplication.class, args);

      }

      @Autowired DataInit initializer;

      @PostConstruct
      public void init() throws  SQLException{

        initializer.insertDataIntoFromDB();
        initializer.insertDataIntoToDB();

      }

Error:

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

Description:

Field toRepository in leadTime.LeadTimeApplication 
required a bean named 'entityManagerFactory' that could not be found.


Action:

Consider defining a bean named 'entityManagerFactory' in your configuration.

I tried: Using

@EnableAutoConfiguration(exclude = { JpaRepositoriesAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class})

Honestly, I don't know what else to do, I re-wrote this code so many times using different approaches but without success. If I let spring to his job, without configuring new entityManagers and transactions and without using @Transactional, the application is working (2 DBs are created), but both tables are created in the sameDB (of course)

Added gradle config

//Spring dependencies
compile "org.springframework.boot:spring-boot-starter- 
actuator:${springBootVersion}"
compile "org.springframework.boot:spring-boot-starter- 
web:${springBootVersion}"
compile "org.springframework.boot:spring-boot-starter- 
logging:${springBootVersion}"
compile "org.springframework.boot:spring-boot-configuration- 
processor:${springBootVersion}"


//JPA dependency
compile "org.springframework.boot:spring-boot-starter-data- 
jpa:${springBootVersion}"

testCompile "com.oracle:ojdbc7:12.1.0.2"
testCompile 'com.h2database:h2:1.4.194'
runtime 'com.h2database:h2:1.4.194'
//  compile group: 'h2', name: 'h2', version: '0.2.0'

compile group: 'org.hibernate', name: 'hibernate-entitymanager'
//compile group: 'org.hibernate', name: 'hibernate-gradle-plugin', version: 
'5.3.6.Final'
// https://mvnrepository.com/artifact/org.hibernate/hibernate-core
compile group: 'org.hibernate', name: 'hibernate-core'
agata
  • 481
  • 2
  • 9
  • 29
  • Clearly you're missing an `EntityManagerFactory` bean definition. – Boris Sep 19 '18 at 09:24
  • But I have two, for each db one: THis should be one of them: @Bean(name = "toEntityManager") public LocalContainerEntityManagerFactoryBean toEntityManagerFactory – agata Sep 19 '18 at 09:39
  • In the [example](https://medium.com/@joeclever/using-multiple-datasources-with-spring-boot-and-spring-data-6430b00c02e7) they use "entityManagerFactory" for the bean name. Can you try it instead of "toEntityManager"? – Boris Sep 19 '18 at 09:39
  • Tried before and now as well: error-> Not a managed type: class leadTime.to.TestDataTo. And I tried to solve it this days by adding EntityScan and so on(move in another package)..but no succes. – agata Sep 19 '18 at 09:50

1 Answers1

0

According to what you have pasted

https://medium.com/@joeclever/using-multiple-datasources-with-spring-boot-and-spring-data-6430b00c02e7

One of the darasource is configured as "default" and another one is named. You are creating two "named" beans with from and to prefixes. Change eg from database definitions entityManager insteed of fromEntityManager and it should be fine.

I don't know the internals, but as for common sense, what you try should work, in practice some default datasource is required by app configurator thus the error.

Antoniossss
  • 31,590
  • 6
  • 57
  • 99
  • As @Boris suggested I tried using "entityManagerFactory". The IDE is telling me that this is a default param and if I am using this I get the following error: Not a managed type: class leadTime.to.TestDataTo. And I tried to solve it this days by adding EntityScan and so on..but no succes – agata Sep 19 '18 at 09:43
  • And now I tried using "entityManager" (only) But I have the same error as before: required a bean named 'entityManagerFactory' that could not be found. – agata Sep 19 '18 at 09:45
  • @Agata - Did you solved your problem? I have the same:( – Matley Mar 18 '19 at 21:51
  • 2
    @Matley, Check this link and put the classes in different packages (this was my porb): https://github.com/spring-projects/spring-data-examples/tree/master/jpa/multiple-datasources – agata Mar 19 '19 at 09:42