Configuring Multiple JPA Entity Managers In Spring Boot


Configuring Multiple JPA Entity Managers In SpringBoot

October 31, 2015 Leave a comment

This blog will demonstrate how to setup multiple entity managers in Spring to connect to different data sources. The solution here also supports Spring Data.

Update Maven Pom file

Include Spring Boot dependency for Spring Data:

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> Disable DataSourceAutoConfiguration

Since we are setting up the data sources, disable the auto configuration in Spring Boot

@[email protected]@EnableAutoConfiguration (exclude = { DataSourceAutoConfiguration.class })public class Application { ... Configure Primary Entity Manager

Below is the Java configuration for the primary entity manager

@Profile("!test")// [email protected]@[email protected](basePackages = "", entityManagerFactoryRef = "entityManager", transactionManagerRef = "transactionManager") // 2public class PrimaryMysqlDBConfiguration {@Bean(name = "dataSource") // [email protected]@ConfigurationProperties(prefix = "primary.datasource.mysql")public DataSource mysqlDataSource() {return DataSourceBuilder.create().build();} @PersistenceContext(unitName = "primary") // [email protected]@Bean(name = "entityManager")public LocalContainerEntityManagerFactoryBean mySqlEntityManagerFactory(EntityManagerFactoryBuilder builder) {return builder.dataSource(mysqlDataSource()).persistenceUnit("primary").properties(jpaProperties()).packages("").build(); }private Map<String, Object> jpaProperties() {Map<String, Object> props = new HashMap<>();props.put("hibernate.ejb.naming_strategy", new SpringNamingStrategy());return props; }} Note: @Profile annotation to use this configuration only for non test profile. This allows me to set a different datasource, e.g. H2, when running tests. @EnableJpaRepositories is used for Spring Data. Note we are using the default transaction manager setup in Spring Bean for primary datasource. [email protected] annotation specifies the prefix of the properties to use by this datasource. For the example here, the file should include properties like below: # DB Connectionprimary.datasource.mysql.url=jdbc:log4jdbc:mysql://localhost/bpmn_serviceprimary.datasource.mysql.username=rootprimary.datasource.mysql.password=rootprimary.datasource.mysql.driver-class-name=net.sf.log4jdbc.DriverSpy Persistence unit name should be setup in the EntityManager bean as shownhere. Configure SecondaryEntity Manager

Configuration of the secondary entity manager is very similar to that of the primary.The only thing is we have to define a new transaction manager. Make sure a different prefix is set in the configuration properties of the data source. Also, a different persistent unit name should be used.

@Profile("!test")@[email protected]@EnableJpaRepositories(basePackages = "", entityManagerFactoryRef = "secondaryMySqlEntityManager", transactionManagerRef = "secondaryTransactionManager")public class SecondaryMysqlDBConfiguration {@[email protected](prefix = "secondary.datasource.mysql") public DataSource mysqlDataSource() {return DataSourceBuilder.create().build(); }@PersistenceContext(unitName = "secondary")@Bean(name = "secondaryMySqlEntityManager")public LocalContainerEntityManagerFactoryBean mySqlEntityManagerFactory(EntityManagerFactoryBuilder builder) { return builder.dataSource(mysqlDataSource()).properties(jpaProperties()).persistenceUnit("secondary").packages("").build(); }@Bean(name = "secondaryTransactionManager") public PlatformTransactionManager transactionManager(EntityManagerFactoryBuilder builder) { JpaTransactionManager tm = new JpaTransactionManager(); tm.setEntityManagerFactory(mySqlEntityManagerFactory(builder).getObject()); tm.setDataSource(mysqlDataSource()); return tm; } private Map<String, Object> jpaProperties() { Map<String, Object> props = new HashMap<>();// naming strategy to put underscores instead of camel case// as per auto JPA Configurationprops.put("hibernate.ejb.naming_strategy", new SpringNamingStrategy());props.put("", "update");return props; }

Note the setup above assumes the primary and secondary data sources are not used together in a single transaction. Hence we can use 2 independent transaction managers.

Specify which Entity Manager to use

Finally, make sure that you specify the name of the secondary transaction in the spring @Transactional annotation:

@Transactional(value = "secondaryTransactionManager")

Also, add the @PersistenceContext annotation with the unit name as defined in the configuration when injecting entity managers;

@PersistenceContext(unitName = "secondary") private EntityManager entityManager;

That’s it!