Multiple databases with Spring Boot and Spring Data JPA

A little while back I knocked up a post describing how to enable a Spring application to connect to multiple data sources. At the time, I had only just heard about Spring Boot at the SpringOne 2GX conference in Santa Clara, so the examples didn’t take advantage of that and also didn’t work around some of the autowiring that it does.

Recently, I was working on a little ETL project to migrate data from one database to another with a different structure, so I returned to this problem and the following is the result.

First, if you want to get hold of a working (including some simple tests) example project, here it is:

https://github.com/gratiartis/multids-demo/tree/now-with-spring-boot

As previously, when you define an entity manager, you can define where it should scan for entities and repository classes. The classes can be named individually, but it is easiest if you put your domain entities and repository classes into their own packages and point the entity manager factory at the package. In this example, I used:

  • com.sctrcd.multids.foo.domain
  • com.sctrcd.multids.foo.repo
  • com.sctrcd.multids.bar.domain
  • com.sctrcd.multids.bar.repo

I suspect that it’s certainly possible to get around it, but I found that due to Spring Boot trying to inject beans based on default names, it was easiest to set up one of the data sources to use the defaults and the other to use bean names that I defined. As you can see in the application.yml below:


spring:
datasource:
url: jdbc:mysql://localhost/foo_schema
username: root
password: d4t4b4s3sForLif3
driverClassName: com.mysql.jdbc.Driver
test-on-borrow: true
test-while-idle: true
validation-query: select 1;
maxActive: 1
jpa:
show-sql: false
generate-ddl: false
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL5InnoDBDialect
ddl-auto: validate
hbm2ddl:
import_files:
bar:
datasource:
url: jdbc:mysql://localhost/bar_schema
username: root
password: d4t4b4s3sForLif3
driverClassName: com.mysql.jdbc.Driver
test-on-borrow: true
test-while-idle: true
validation-query: select 1;
maxActive: 1

view raw

application.yml

hosted with ❤ by GitHub

… the spring.datasource.url, spring.datasource.username and spring.datasource.password properties are all defined for the ‘default’ datasource. I define some additional non-conventional properties for the additional schema. We will see how those are picked up shortly.

Beyond the application.yml configuration, all we need to do is define @Configuration beans which will pick up the properties. First, a @Configuration to wire up the ‘default’ data source. This defines each bean as @Primary, to ensure that they are the beans picked up by anything which does not specify a @Qualifier:


package com.sctrcd.multidsdemo;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactory",
basePackages = { "com.sctrcd.multidsdemo.foo.repo" })
public class FooConfig {
@Primary
@Bean(name = "dataSource")
@ConfigurationProperties(prefix="spring.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
@Primary
@Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
EntityManagerFactoryBuilder builder,
@Qualifier("dataSource") DataSource dataSource) {
return builder
.dataSource(dataSource)
.packages("com.sctrcd.multidsdemo.foo.domain")
.persistenceUnit("foo")
.build();
}
@Primary
@Bean(name = "transactionManager")
public PlatformTransactionManager transactionManager(
@Qualifier("entityManagerFactory") EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
}

Second a @Configuration to wire up the additional datasource. It is essentially identical to the ‘default’ configuration, except that it defines non-conventional names for the data source, entity manager factory and transaction manager and scans different packages for the entities and repositories. It also defines the named transaction manager in the @EnableJpaRepositories annotation and does not define the beans as @Primary.


package com.sctrcd.multidsdemo;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "barEntityManagerFactory",
transactionManagerRef = "barTransactionManager",
basePackages = { "com.sctrcd.multidsdemo.bar.repo" })
public class BarConfig {
@Bean(name = "barDataSource")
@ConfigurationProperties(prefix="bar.datasource")
public DataSource barDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "barEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean barEntityManagerFactory(
EntityManagerFactoryBuilder builder,
@Qualifier("barDataSource") DataSource barDataSource) {
return builder
.dataSource(barDataSource)
.packages("com.sctrcd.multidsdemo.bar.domain")
.persistenceUnit("bar")
.build();
}
@Bean(name = "barTransactionManager")
public PlatformTransactionManager barTransactionManager(
@Qualifier("barEntityManagerFactory") EntityManagerFactory barEntityManagerFactory) {
return new JpaTransactionManager(barEntityManagerFactory);
}
}

Beyond those configuration classes, everything is just the standard setup for a Spring Boot / Spring Data JPA application, so if you have an application connecting to a single database already, there isn’t a lot of modification to support connecting to additional databases.

62 thoughts on “Multiple databases with Spring Boot and Spring Data JPA

  1. Hi, I’m have a similar problem. Over stackoverflow i found your blog post. One thing, you write that in the second config should not define as primary, but you do it in the example.

    I implemented your solution but it didn’t work, my JpaRepo (Interface) has the wrong entityManager (from the base, but i need the second). Have you andy idea how could it be resolved? If you like i can add the link to stackoverflow.

    Thank’s in advance.

    Like

    1. Thanks for pointing that out. When I created the Gist, I copied the default config instead of basing it on my working code. Doh! I had removed the @Primary annotation from the datasource, but not the other beans. It’s fixed now. 🙂

      If you have the code available somewhere public I’d be happy to take a look. There may be something I should add to the blog post, which I missed.

      Like

  2. Hi, very interesting post! Exactly what I’m looking for. I have referred your working example here https://github.com/gratiartis/multids-demo/tree/now-with-spring-boot and tried the same. but I’m facing the below exception always! Do you have any clue on this?

    2016-02-11 16:50:02.773 INFO 5156 — [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [
    name: external
    …]
    2016-02-11 16:50:02.907 INFO 5156 — [ main] org.hibernate.Version : HHH000412: Hibernate Core {4.3.11.Final}
    2016-02-11 16:50:02.911 INFO 5156 — [ main] org.hibernate.cfg.Environment : HHH000206: hibernate.properties not found
    2016-02-11 16:50:02.914 INFO 5156 — [ main] org.hibernate.cfg.Environment : HHH000021: Bytecode provider name : javassist
    2016-02-11 16:50:03.257 INFO 5156 — [ main] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {4.0.5.Final}
    2016-02-11 16:50:03.464 WARN 5156 — [ main] o.a.tomcat.jdbc.pool.PooledConnection : Not loading a JDBC driver as driverClassName property is null.
    2016-02-11 16:50:03.498 ERROR 5156 — [ main] o.a.tomcat.jdbc.pool.ConnectionPool : Unable to create initial connections of pool.

    java.sql.SQLException: The url cannot be null
    at java.sql.DriverManager.getConnection(DriverManager.java:649) ~[na:1.8.0_60]
    at java.sql.DriverManager.getConnection(DriverManager.java:208) ~[na:1.8.0_60]
    at org.apache.tomcat.jdbc.pool.PooledConnection.connectUsingDriver(PooledConnection.java:305) ~[tomcat-jdbc-8.0.30.jar:na]
    at org.apache.tomcat.jdbc.pool.PooledConnection.connect(PooledConnection.java:200) ~[tomcat-jdbc-8.0.30.jar:na]
    at org.apache.tomcat.jdbc.pool.ConnectionPool.createConnection(ConnectionPool.java:708) [tomcat-jdbc-8.0.30.jar:na]
    at org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:642) [tomcat-jdbc-8.0.30.jar:na]
    at org.apache.tomcat.jdbc.pool.ConnectionPool.init(ConnectionPool.java:464) [tomcat-jdbc-8.0.30.jar:na]
    at org.apache.tomcat.jdbc.pool.ConnectionPool.(ConnectionPool.java:141) [tomcat-jdbc-8.0.30.jar:na]
    at org.apache.tomcat.jdbc.pool.DataSourceProxy.pCreatePool(DataSourceProxy.java:115) [tomcat-jdbc-8.0.30.jar:na]
    at org.apache.tomcat.jdbc.pool.DataSourceProxy.createPool(DataSourceProxy.java:102) [tomcat-jdbc-8.0.30.jar:na]
    at org.apache.tomcat.jdbc.pool.DataSourceProxy.getConnection(DataSourceProxy.java:126) [tomcat-jdbc-8.0.30.jar:na]
    at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:139) [hibernate-core-4.3.11.Final.jar:4.3.11.Final]
    at org.hibernate.engine.jdbc.internal.JdbcServicesImpl$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcServicesImpl.java:279) [hibernate-core-4.3.11.Final.jar:4.3.11.Final]
    at org.hibernate.engine.jdbc.internal.JdbcServicesImpl.configure(JdbcServicesImpl.java:124) [hibernate-core-4.3.11.Final.jar:4.3.11.Final]
    at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:111) [hibernate-core-4.3.11.Final.jar:4.3.11.Final]
    at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:234) [hibernate-core-4.3.11.Final.jar:4.3.11.Final]
    at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:206) [hibernate-core-4.3.11.Final.jar:4.3.11.Final]
    at org.hibernate.cfg.Configuration.buildTypeRegistrations(Configuration.java:1887) [hibernate-core-4.3.11.Final.jar:4.3.11.Final]
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1845) [hibernate-core-4.3.11.Final.jar:4.3.11.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:857) [hibernate-entitymanager-4.3.11.Final.jar:4.3.11.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:850) [hibernate-entitymanager-4.3.11.Final.jar:4.3.11.Final]
    at org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl.withTccl(ClassLoaderServiceImpl.java:425) [hibernate-core-4.3.11.Final.jar:4.3.11.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:849) [hibernate-entitymanager-4.3.11.Final.jar:4.3.11.Final]
    at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:60) [spring-orm-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFa
    ctoryBean.java:343) [spring-orm-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:318) [spring-orm-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1637) [spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574) [spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:545) [spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) [spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) [spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) [spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) [spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) [spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1054) [spring-context-4.2.4.RELEASE.jar:4.2.4.RELEASE]

    Like

  3. How are you running it? It looks like the application.yml in the config directory might not have been loaded, as that provides things like the URL for the database.

    Note that there is a SQL script in the ‘db’ directory, which creates the two schemas that the application will try to connect to. Assuming that you are testing with MySQL, then that script should work, and a few tweaks to the application.yml (change URL, passwords, etc for your local config) should let you connect to it.

    Like

    1. Nice work. Hopefully it was easy enough! btw – In case you hadn’t seen them, you can set properties such as spring.datasource.min-idle, spring.datasource.max-idle and spring.datasource.max-active to control how many connections there are in each pool.

      Like

  4. Thanks, I need this to setup 4 database connections = 4 datasources. There are pieces here I need to incorporate to make it work. Appreciate the details!

    Like

  5. Seems to be exactly what I need. But where does EntityManagerFactoryBuilder come from? When I try to launch the code, I get the exception:
    “Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}”

    Should I define the bean myself of somehow ask Spring to do it for me?

    Like

    1. Spring should be injecting that for you, but that message indicates that the application isn’t being wired up correctly. Maybe your database config has an error, which means that Spring is unable to create the beans relating to it?

      Also, are you running as a Spring Boot application? If not, then as xtreye mentions below, you may need to do some of the additional configuration described in my previous post: https://scattercode.co.uk/2013/11/18/spring-data-multiple-databases/

      Like

  6. Seem to be exactly what I need, but could you please tell where does EntityManagerFactoryBuilder come from?
    I am asking because I getting message “No qualifying bean of type [org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder] found for dependency” when try to use this solution. I do not use @SpringBootApplication because this not the app but one of the modules.

    Like

  7. as i can see there is only one jpa. can you help me how to import 2 or 3 JPAs (one for oracle and another for mysql)?

    Like

    1. Above, both datasources defined in application.yml are using the MySQL driver. Just put the Oracle drivers on the classpath and change one of the datasources to use them. You shouldn’t need to change anything anywhere else.

      Like

  8. Hi,
    I did the same configuration as you did. But getting the following exception.
    Could you please provide your inputs.

    Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 2: barEntityManagerFactory,entityManagerFactory
    at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findDefaultEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:572)
    at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:531)
    at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$PersistenceElement.resolveEntityManager(PersistenceAnnotationBeanPostProcessor.java:697)
    at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$PersistenceElement.getResourceToInject(PersistenceAnnotationBeanPostProcessor.java:670)
    at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:169)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
    at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.postProcessPropertyValues(PersistenceAnnotationBeanPostProcessor.java:354)

    Like

  9. org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘genericDaoImpl’: Injection of persistence dependencies failed; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 2: barEntityManagerFactory,entityManagerFactory
    at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.postProcessPropertyValues(PersistenceAnnotationBeanPostProcessor.java:357)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1210)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:755)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:686)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:957)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:946)

    Like

    1. Unfortunately not. This works by using Spring’s @EnableJpaRepositories annotation to define the package which should be scanned to find repositories for each data source and inject entity and transaction managers. So anything in the same package will use the same data source.

      Like

  10. Hi, I’m implementing your example and I’m able to start my spring boot application without errors but at runtime I have this error:

    ERROR: Bean named ‘entityManagerFactory’ must be of type [org.springframework.transaction.PlatformTransactionManager], but was actually of type [com.sun.proxy.$Proxy81]

    It seems that I applied all your indications, what’s wrong?

    Thanks

    Like

    1. It’s hard to say. That error usually means that for some reason Spring is unable to use CGLIB. Going by a quick look at StackOverflow, sometimes also, a third party tool, such as Cobertura could be manipulating your bytecode to replace references to concrete classes with proxies.

      Like

  11. FYI, to use non-default values for the naming strategy etc I had to do the following (the property values don’t need to be hard-coded, obviously). There may be a better way to do this….

    @Bean(name = “barEntityManagerFactory”)
    public LocalContainerEntityManagerFactoryBean barEntityManagerFactory(
    EntityManagerFactoryBuilder builder,
    @Qualifier(“barDataSource”) DataSource barDataSource) {

    HashMap properties = new HashMap();
    properties.put(“hibernate.hbm2ddl.auto”, “update”);
    properties.put(“hibernate.dialect”, “org.hibernate.dialect.PostgreSQL9Dialect”);
    properties.put(“hibernate.ejb.naming_strategy”, “org.hibernate.cfg.EJB3NamingStrategy”);

    return builder
    .dataSource(barDataSource)
    .packages(“com.sctrcd.multidsdemo.bar.domain”)
    .persistenceUnit(“bar”)
    .properties(properties)
    .build();
    }

    Like

  12. Thanks for the great sample. It seems like it breaks chacheManager autoconfig. Any idea how to fix this?

    pringframework.beans.factory.NoSuchBeanDefinitionException: No bean named ‘cacheManager’ is defined
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:702)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1180)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:284)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:296)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1076)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:851)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:541)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:759)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:369)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:313)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1185)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1174)
    at com.wiser.WpmApplication.main(WpmApplication.java:20)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)

    Like

  13. Hey , Why does spring boot throw this expection –> “Caused by: java.lang.IllegalArgumentException: Repository interface must not be null on initialization!

    Like

  14. Hi sctrcdr,
    I have implemented Multi data-source using spring boot. I have a requirement to 20 data sources. Is there any way i can implement dynamically with out include all the data sources in below config class?

    Please advice, much appreciated. Thanks

    DataSourceConfig.java

    @Bean(name = “ds-aus”)
    @Primary
    @ConfigurationProperties(prefix=”spring.datasource”)
    public DataSource dataSourceAUS() {
    return DataSourceBuilder.create().build();
    }

    @Bean(name = “ds-ind”)
    @ConfigurationProperties(prefix=”spring.datasource.cl”)
    public DataSource dataSourceIND() {
    return DataSourceBuilder.create().build();
    }
    • Reply•Share ›

    Like

    1. hi narendra,
      Could you please share me examples :
      Based on user request the different mysql DataBases connection using Spring boot JPA using Spring liquibase and HikariDataSource (Two mysql DataBases)

      Like

  15. Great article. This addresses exactly what I’m having trouble with right now, however I’m still getting “Not a managed type” exception for one of my entities. Interestingly enough, the entity that gets this exception is the one that does not have the LocalContainerEntityManagerFactoryBean named “entityManagerFactory” (I’ve named the other config’s bean “entityManagerFactory” and the other entity became the unmanaged type). All the properties in both config’s @EnableJpaProperties are set correctly. I’ve also tried to specify bean names as you outlined in your other article, in which case I receive the “No bean named ‘entityManagerFactory’ is defined” error.

    Other info: I’m using spring boot. One datasource is MySQL and the other is Vertica. If I isolate either datasource in my project everything works as expected.

    Have you ever run in to this or have any idea why this might be happening? Thanks in advance.

    Like

    1. Do you have your repositories and entities in separate packages, so that you can ensure that classpath scanning doesn’t pick up the wrong ones?

      And the correct path to the domain entities in the LocalContainerEntityManagerFactoryBean definitions?

      Like

      1. Thanks for your very prompt response. I figured out the issue – I had too many annotations in my main method. Specifically, I had @SpringBootApplication while also having @ComponentScan and @EntityScan… I removed everything but @SpringBootApplication and everything finally worked!

        Like

    2. I’m facing same issue for now. Need to use mongo db as well as vertica db in same application. Not sure how should i configure. If you/anyone have found a way, can you/anyone please help?

      Like

  16. Great article. This addresses exactly what I’m having trouble with right now, however I’m still getting “Not a managed type” exception for one of my entities. Interestingly enough, the entity that gets this exception is the one that does not have the LocalContainerEntityManagerFactoryBean named “entityManagerFactory” (I’ve named the other config’s bean “entityManagerFactory” and the other entity became the unmanaged type). All the properties in both config’s @EnableJpaProperties are set correctly. I’ve also tried to specify bean names as you outlined in your other article, in which case I receive the “No bean named ‘entityManagerFactory’ is defined” error.

    Other info: I’m using spring boot. One datasource is MySQL and the other is Vertica. If I isolate either datasource in my project everything works as expected.

    Have you ever run in to this or have any idea why this might be happening? Thanks in advance.

    Like

  17. We have struggled for days to get two data sources to work in a Spring Boot application. This approach seems like the most sane, but we still cannot make it work. As far as I can see we have followed the pattern exactly, but the application fails to create the second repository with this error:

    Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘lookupRestController’ defined in file [/home/nils/workspace/RAÄ/platsr-sb/platsrapi/build/classes/main/se/raa/platsr/controller/LookupRestController.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘lookupService’ defined in file [/home/nils/workspace/RAÄ/platsr-sb/platsrapi/build/classes/main/se/raa/platsr/service/LookupService.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘LMPlaceRepository’: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not a managed type: class se.raa.platsr.model.lookup.LMPlace

    I thought the .packages(…) call here should take care of that:

    @Bean(name = “lookupEntityManagerFactory”)
    public LocalContainerEntityManagerFactoryBean lookupEntityManager(final EntityManagerFactoryBuilder builder,
    @Qualifier(“lookupDataSource”) final DataSource dataSource) {
    return builder.dataSource(dataSource).packages(“se.raa.platsr.model.lookup”).persistenceUnit(“lookup”).build();
    }

    So, what is it that I don’t understand/have missed out?

    Like

  18. We have spent two days getting two data sources to work in a Spring Boot application. This approach is the sanest we have found, but we still cannot get it to work. We get this for an Entity class to be managed by the secondary data source/entity manager:

    Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘lookupRestController’ defined in file [/home/nils/workspace/RAÄ/platsr-sb/platsrapi/build/classes/main/se/raa/platsr/controller/LookupRestController.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘lookupService’ defined in file [/home/nils/workspace/RAÄ/platsr-sb/platsrapi/build/classes/main/se/raa/platsr/service/LookupService.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘LMPlaceRepository’: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not a managed type: class se.raa.platsr.model.lookup.LMPlace

    I thought this would be adressed by the call to .packages(…) in the EntityManagerFactory builder:

    @Bean(name = “lookupEntityManagerFactory”)
    public LocalContainerEntityManagerFactoryBean entityManager(final EntityManagerFactoryBuilder builder,
    @Qualifier(“lookupDataSource”) DataSource dataSource) {
    return builder.dataSource(dataSource).packages(LMPlace.class).persistenceUnit(“lookup”).build();
    }

    I have tried with a package name as well

    @Bean(name = “lookupEntityManagerFactory”)
    public LocalContainerEntityManagerFactoryBean entityManager(final EntityManagerFactoryBuilder builder,
    @Qualifier(“lookupDataSource”) DataSource dataSource) {
    return builder.dataSource(dataSource).packages(“se.raa.platsr.model.lookup”).persistenceUnit(“lookup”).build();
    }

    with no success. So, what can it be that I don’t understand, or have configured wrong? The error comes from the initialization of a class that should use this configuration:

    @Service
    @Transactional(“lookupTransactionManager”)
    public class LookupService {

    Is this where we are going wrong?

    Like

    1. It looks like the problem is with detecting se.raa.platsr.model.lookup.LMPlace as an @Entity. As in my example, I’d change that LCEMFB implementation to be an EntityManagerFactory and use setPackagesToScan to point at se.raa.platsr.model.lookup. It’s generally better to return an interface rather than an implementation.

      Like

  19. Great! Thanks for sharing.

    I have a question. My project structure is like this:

    com.app.controller
    com.app.service

    com.app.domain
    com.app.domain.Foo1
    com.app.domain.Foo2
    com.app.domain.Foo3
    com.app.domain.Bar1
    com.app.domain.Bar2
    com.app.domain.Bar3

    com.app.repository
    com.app.repository.Foo1Repository
    com.app.repository.Foo3Repository
    com.app.repository.Foo2Repository
    com.app.repository.Bar1Repository
    com.app.repository.Bar2Repository
    com.app.repository.Bar3Repository

    as you suggest it should be structured like this?:

    com.app.controller
    com.app.service

    com.app.Foo1.domain
    com.app.Foo1.repository
    com.app.Foo2.domain
    com.app.Foo2.repository
    com.app.Foo3.domain
    com.app.Foo3.repository
    com.app.Bar1.domain
    com.app.Bar1.repository
    com.app.Bar2.domain
    com.app.Bar2.repositroy
    com.app.Bar3.domain
    com.app.Bar3.repository

    And if i have 50 classes to deal with databases i need 50 packeges each (an additionaly 2: domain and repo)?

    Ani idea how to do it right?

    Thanks

    Like

    1. You don’t need a separate package for each entity. Just a separate package for each database. So more like:

      com.app.foo.domain.Foo1
      com.app.foo.repository.Foo1Repository
      com.app.bar.domain.Bar1
      etc…

      Like

  20. bar:
    datasource:
    url: jdbc:mysql://localhost/bar_schema
    username: root
    password: d4t4b4s3sForLif3
    driverClassName: com.mysql.jdbc.Driver
    test-on-borrow: true \\ in spring boot 1.5.3 it seems this is moved under tomcat.
    test-while-idle: true \\ but when I tried something like below it is not working can anyone please help?
    validation-query: select 1;\\

    bar:
    datasource:
    url: jdbc:mysql://localhost/bar_schema
    username: root
    password: d4t4b4s3sForLif3
    driverClassName: com.mysql.jdbc.Driver
    tomcat:
    test-on-borrow: true
    test-while-idle: true
    validation-query: select 1;

    Like

    1. I’m happy to hear that you were able to use the examples so easily. Please feel free to make use of it in your blog in Spanish. If it helps more people to do this, then that’s all good! Please do let me know if you do that and I shall link to it.

      Like

  21. Hello sir, I am trying to configure multiple databases, I am getting the following exception while inserting the data to table

    AddressTypeID –>> is Auto incremented in DB, i have given AUTO here still it is throwing this exception?? please help me. thank you.

    com.microsoft.sqlserver.jdbc.SQLServerException: Cannot insert explicit value for identity column in table ‘AddressTypeMaster’ when IDENTITY_INSERT is set to OFF.
    at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(SQLServerException.java:232) ~[mssql-jdbc-6.1.0.jre7.jar:?]

    @Entity
    @Table(name = “AddressTypeMaster”)
    public class AddressType implements Serializable{
    /**
    *
    */
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = “AddressTypeID”)
    private Integer addressTypeID;
    @Column(name = “AddressTypeName”)
    private String addressTypeName;
    @Column(name = “IsActive”)
    private Boolean isActive;
    @Column(name = “CreatedOn”)
    private Date createdOn;
    @Column(name = “CreatedBy”)

    Like

    1. Hi there. That looks like you have your database table configured to auto-increment, with “IDENTITY_INSERT” disabled. This means that your application cannot insert an ID itself.

      One option is to change it to GenerationType.Identity. That will let SQL Server do the ID generation for you.

      However, GenerationType.AUTO *should* work. One reason this can fail is if you’re not using the most recent dialect supported by Hibernate. It would be worth checking exactly which version of SQL Server you are using and set jpa.properties.hibernate.dialect appropriately. It should be the most recent dialect supported by your database, from:

        org.hibernate.dialect.SQLServerDialect
        org.hibernate.dialect.SQLServer2005Dialect
        org.hibernate.dialect.SQLServer2008Dialect
        org.hibernate.dialect.SQLServer2012Dialect

      If that is the problem, then by updating it, you’ll also get access to lots of nice field types that weren’t available to you before! 🙂

      Like

  22. Nicely written. Very helpful. Quick question – where are CRUD operations using repositories? Where should we declare DAO. Request you to add those examples.

    Like

    1. A Spring Data repository is a DAO. You don’t need to write one of your own, although you can extend them with your own implementations if some of the standard methods are not sufficient.

      Like

  23. spring:
    datasource:
    url: jdbc:mysql://localhost/foo_schema
    username: foouser
    password: 12345
    driverClassName: com.mysql.jdbc.Driver

    bar:
    datasource:
    url: jdbc:mysql://localhost/bar_schema
    username: baruser
    password: 12345
    driverClassName: com.mysql.jdbc.Driver

    How to connect to database with there different users (like above config properties )

    Like

  24. Hi,
    I have connected to the two datasources, but I want different operations to be done by both the datasources.
    Ex.
    for Primary datasoure- only write/update/delete operations should be done.
    for Secondary datasource- only read operation should be done.
    — (the database and tables are same so the repository also same.)

    In my code both operations goes to primary datasource. could you please let me know how this can be done, or any working reference so it will be helpful for me.

    Thanks,
    Sandeep.

    Like

  25. Description:

    Parameter 0 of method entityManagerFactoryBean in com.example.anil.config.BookDBConfig required a bean of type ‘org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder’ that could not be found.

    Action:

    Consider defining a bean of type ‘org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder’ in your configuration.

    Like

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.