Search code examples
javaspringentitymanagerpersistence.xml

Multiple entityManagerFactory without persistence.xml


I've been working in a project that has been using spring mvc 4 and JPA configuration beans are created in java class without persistence.xml just like the code below.

package test.conf;

import java.util.Properties;
import javax.persistence.EntityManagerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
public class JPAConfiguration {

    @Bean
    @Primary
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
        JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();

        factoryBean.setJpaVendorAdapter(vendorAdapter);
        factoryBean.setDataSource(dataSource());    

        Properties props = new Properties();
        props.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
        props.setProperty("hibernate.show_sql", "false");
        props.setProperty("hibernate.hbm2ddl.auto", "update");

        factoryBean.setJpaProperties(props);
        String [] packages = {"test.model"};
        factoryBean.setPackagesToScan(packages);

        return factoryBean;
    }

    @Bean
    @Primary
    public DriverManagerDataSource dataSource() {

        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        dataSource.setUrl("jdbc:mysql://localhost:3306/database");
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        return dataSource;
    }

    @Bean
    @Primary
    public JpaTransactionManager transactionManager(EntityManagerFactory emf){
        return new JpaTransactionManager(emf);
    }

}

This is working fine, but now, we will have to connect to a second database (ORACLE) and there will be necessary a second entity manager factory. How can I do this ? I have found examples creating a second persistence unit on persistence.xml but I don't have the persistence.xml in that project. Others teach how to create connection to multiple datasources using spring boot, but this isn't a spring boot project.

I tried to create a second JPAConfiguration class for the other database and then specifying a factoryBean.setPersistenceUnitName(""); for each entitymanagerfactorybean, but seems that Spring is messing up since it always initializes one the persiscence unit twice.


Solution

  • You need have second datasource details in properties

    #second db ...
    spring.secondDatasource.url = [url]
    spring.secondDatasource.username = [username]
    spring.secondDatasource.password = [password]
    spring.secondDatasource.driverClassName = oracle.jdbc.OracleDriver
    

    Then create your configuration class that will have all configuration to use this second datasource and enable jpa repositry with this second datasource.

    @Configuration
    @EnableTransactionManagement
    @EnableJpaRepositories(entityManagerFactoryRef = "secondEntityManagerFactory",
            transactionManagerRef = "secondTransactionManager",
            basePackages = {"com.server.second.repo"}
    )
    public class SecondDBConfiguration  
    
    @Bean("secondDatasource")
    @ConfigurationProperties(prefix="spring.secondDatasource")
    public DataSource secondaryDataSource() {
    return DataSourceBuilder.create().build();
    }
    
    @Bean(name = "secondEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean
    secondEntityManagerFactory(
            EntityManagerFactoryBuilder builder,
            @Qualifier("secondDatasource") DataSource dataSource
    ) {
        return
                builder
                        .dataSource(dataSource)
                        .packages("com.server.shadow.domain")
                        .persistenceUnit("shadow")
                        .build();
    }
    @Bean(name = "secondTransactionManager")
    public PlatformTransactionManager secondTransactionManager(
            @Qualifier("secondEntityManagerFactory") EntityManagerFactory
                    secondEntityManagerFactory
    ) {
        return new JpaTransactionManager(secondEntityManagerFactory);
    }