36

I'm using Spring Boot. I finally managed to setup two data sources, but now I'm facing another issue.

  1. with two data sources in place spring.jpa.hibernate.ddl-auto=create seems to stop working in my spring boot application, only spring.jpa.generate-ddl=true do the job now

  2. I can not manage to select the auto-creation strategy for each of the data sources. I would prefer to create the schema for data source one, and just use the created schema in second DB with data source two.

Any body have idea how to resolve any of these issues? Note I don't want to completely throw away the auto-config if possible. I don't even know yet, if hibernate is able to just initialize schema in one persistence unit.

application.properties

spring.datasource-internal.url=jdbc:hsqldb:mem:testdb
spring.datasource-internal.username=sa
spring.datasource-internal.password=sa
spring.datasource-internal.driver-class-name=org.hsqldb.jdbcDriver
spring.datasource-internal.jpa.database-platform=org.hibernate.dialect.HSQLDialect

spring.datasource-external.url=jdbc:hsqldb:mem:testexternal
spring.datasource-external.username=sa
spring.datasource-external.password=sa
spring.datasource-external.driver-class-name=org.hsqldb.jdbcDriver
spring.datasource-external.jpa.database-platform=org.hibernate.dialect.HSQLDialect

flyway.enabled=false
spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true
spring.jpa.generate-ddl=true

DBInternalConfig


    @Configuration
    @EnableTransactionManagement
    @EnableJpaRepositories(basePackages = "cz.data.internal",
            entityManagerFactoryRef = "internalEntityManagerFactory",
            transactionManagerRef = "internalTransactionManager")
    public class DBConfigInternal {


        public static final String INTERNAL = "internal";

        @Bean(name = "internalDataSource")
        @Primary
        @ConfigurationProperties(prefix = "spring.datasource-internal")
        public DataSource internalDataSource() {
            return DataSourceBuilder.create().build();
        }

        @Bean(name = "internalEntityManagerFactory")
        @Primary
        public LocalContainerEntityManagerFactoryBean internalEntityManagerFactory(
                EntityManagerFactoryBuilder builder) {
            return builder
                    .dataSource(internalDataSource())
                    .packages("cz.data.internal.entity")
                    .persistenceUnit(INTERNAL)
                    .build();
        }

        @Bean(name = "internalTransactionManager")
        @Primary
        public PlatformTransactionManager internalTransactionManager() {
            JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
            jpaTransactionManager.setDataSource(internalDataSource());
            jpaTransactionManager.setPersistenceUnitName(INTERNAL);
            return jpaTransactionManager;
        }
    }

DBExternalConfig


    @Configuration
    @EnableTransactionManagement
    @EnableJpaRepositories(
            basePackages = "cz.data.external",
            entityManagerFactoryRef = "externalEntityManagerFactory",
            transactionManagerRef = "externalTransactionManager")
    public class DBConfigExternal {


        public static final String EXTERNAL = "external";

        @Bean(name = "externalDataSource")
        @ConfigurationProperties(prefix = "spring.datasource-external")
        public DataSource externalDataSource() {
            return DataSourceBuilder.create().build();
        }

        @Bean(name = "externalEntityManagerFactory")
        public LocalContainerEntityManagerFactoryBean externalEntityManagerFactory(
                EntityManagerFactoryBuilder builder) {
            return builder
                    .dataSource(externalDataSource())
                    .packages("cz.data.external.entity")
                    .persistenceUnit(EXTERNAL)
                    .build();
        }

        @Bean(name = "externalTransactionManager")
        public PlatformTransactionManager externalTransactionManager() {
            JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
            jpaTransactionManager.setDataSource(externalDataSource());
            jpaTransactionManager.setPersistenceUnitName(EXTERNAL);
            return jpaTransactionManager;
        }
    }

M.W.

mate00
  • 2,727
  • 5
  • 26
  • 34
Zveratko
  • 2,663
  • 6
  • 35
  • 64
  • There's no reason why `spring.jpa.hibernate.ddl-auto=create` should stop working purely because you have two DataSources. Spring Boot will simply auto-configure Hibernate to use whichever DataSource is `@Primary`. I would guess that you've added some additional configuration that's switched off the auto-configuration of Hibernate but it's impossible to tell as you haven't provided enough information to recreate the issues that you're trying to resolve. – Andy Wilkinson Feb 02 '15 at 13:26
  • I have added some code snippets. I'm not very clear about the two options at all, I hardly see where they are even set up, no to mention where exactly they are hooked to the code. Anyway more important for me is the second issue, how to make it datasource specific. – Zveratko Feb 02 '15 at 13:54
  • Check this link http://docs.spring.io/spring-boot/docs/current/reference/html/howto-database-initialization.html#howto-execute-flyway-database-migrations-on-startup – Eddú Meléndez Feb 02 '15 at 14:23
  • I'm aware of this documentation. I want to be able to use auto generation, anyway I don't see option to use different flyway scripts for different data sources. I want to be able to initialize both data sources independently. – Zveratko Feb 02 '15 at 14:35
  • maybe something like this http://stackoverflow.com/a/13625889/2944265 , need to check how Spring Boot likes that:-/ – Zveratko Feb 02 '15 at 14:44

1 Answers1

50

spring.jpa.hibernate.ddl-auto=create has stopped working, not because you have two DataSources, but because your application's creating its own LocalContainerEntityManagerFactoryBeans. This has the effect of disabling the auto-configuration of a LocalContainerEntityManagerFactoryBean so you now have to configure it yourself.

You can configure the two entity managers to have different schema generation behaviour like this (the first's doing update, the second's doing create):

@Bean(name = "externalEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean externalEntityManagerFactory(
        EntityManagerFactoryBuilder builder) {
    Map<String, Object> properties = new HashMap<String, Object>();
    properties.put("hibernate.hbm2ddl.auto", "update");
    return builder
            .dataSource(externalDataSource())
            .packages("cz.data.external.entity")
            .persistenceUnit(EXTERNAL)
            .properties(properties)
            .build();
}

@Bean(name = "internalEntityManagerFactory")
@Primary
public LocalContainerEntityManagerFactoryBean internalEntityManagerFactory(
        EntityManagerFactoryBuilder builder) {
    Map<String, Object> properties = new HashMap<String, Object>();
    properties.put("hibernate.hbm2ddl.auto", "create");
    return builder
            .dataSource(internalDataSource())
            .packages("cz.data.internal.entity")
            .persistenceUnit(INTERNAL)
            .properties(properties)
            .build();
}
Andy Wilkinson
  • 108,729
  • 24
  • 257
  • 242
  • I have followed your advice. The application seems to be working, but strange thing is I'm not able to see the tables in hsqldb(in memory), shouldn't it be possible that I screwed also something with transactions. So the transaction is still opened and not commited yet?:( – Zveratko Feb 02 '15 at 16:19
  • 2
    I'm also getting lots of `org.hibernate.tool.hbm2ddl.SchemaExport : user lacks privilege or object not found: PUBLIC.NOTIFICATION` – Zveratko Feb 02 '15 at 16:23
  • 1
    Seems the HSQLDB process is not available to other [link](http://stackoverflow.com/a/5080465/2944265) – Zveratko Feb 02 '15 at 16:35
  • Can you please add the XML based configuration – devanathan Feb 15 '16 at 07:30
  • @Andy - Could you please guide me here: https://stackoverflow.com/questions/61086749/spring-batch-unable-to-create-metadata-tables-on-postgres-and-load-actual-data ? – PAA Apr 07 '20 at 18:22