In this official example of configuring 2 data sources, they have used embedded DB. So, with the help of Spring boot's How to documentations, Configure Two DataSources and Using Multiple EntityManagerFactories, I customized that to use MySQL DB.
You can find the complete code under this Github repository. Don't forget to checkout the "two_data_sources_in_separate_files" branch.
But with this modification, "secondDBTransactionManager" is not pointing second_db. Instead, it is inserting data into first_db.
FirstDataSource.java
@Configuration
@EnableJpaRepositories(entityManagerFactoryRef = "firstDBEntityManagerFactory", transactionManagerRef = "firstDBTransactionManager")
public class FirstDataSource {
@Bean
PlatformTransactionManager firstDBTransactionManager(DataSourceProperties firstDataSourceProperties) {
return new JpaTransactionManager(firstDBEntityManagerFactory(firstDataSourceProperties).getObject());
}
@Bean
@Primary
LocalContainerEntityManagerFactoryBean firstDBEntityManagerFactory(DataSourceProperties firstDataSourceProperties) {
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
jpaVendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(firstDS(firstDataSourceProperties));
factoryBean.setJpaVendorAdapter(jpaVendorAdapter);
factoryBean.setPackagesToScan(FirstDataSource.class.getPackage().getName());
return factoryBean;
}
@Bean
@Primary
@ConfigurationProperties("app.datasource.first")
public DataSourceProperties firstDataSourceProperties() {
return new DataSourceProperties();
}
@Bean
@Primary
@ConfigurationProperties("app.datasource.first.configuration")
public HikariDataSource firstDS(DataSourceProperties firstDataSourceProperties) {
return firstDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
}
}
SecondDataSource.java
@Configuration
@EnableJpaRepositories(entityManagerFactoryRef = "secondDBEntityManagerFactory", transactionManagerRef = "secondDBTransactionManager")
public class SecondDataSource {
@Bean
PlatformTransactionManager secondDBTransactionManager(DataSourceProperties secondDataSourceProperties) {
return new JpaTransactionManager(secondDBEntityManagerFactory(secondDataSourceProperties).getObject());
}
@Bean
@ConfigurationProperties("app.datasource.second")
public DataSourceProperties secondDataSourceProperties() {
return new DataSourceProperties();
}
@Bean
@ConfigurationProperties("app.datasource.second.configuration")
public HikariDataSource secondDS(
@Qualifier("secondDataSourceProperties") DataSourceProperties secondDataSourceProperties) {
return secondDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
}
@Bean
public LocalContainerEntityManagerFactoryBean secondDBEntityManagerFactory(DataSourceProperties secondDataSourceProperties) {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(secondDS(secondDataSourceProperties));
factoryBean.setJpaVendorAdapter(vendorAdapter);
factoryBean.setPackagesToScan(SecondDataSource.class.getPackage().getName());
return factoryBean;
}
}
FetchData.java
@Controller // This means that this class is a Controller
@RequestMapping(path = "/demo") // This means URL's start with /demo (after Application path)
public class FetchData {
@Autowired
private TableARepository tableARepository;
@Autowired
private TableCRepository tableCRepository;
@GetMapping(path = "/addDataToFirstDB")
public @ResponseBody void addDataToFirstDB() {
// This returns a JSON or XML with the users
Table_A tableA = new Table_A();
tableA.setTable_a_col_1("test1");
tableA.setTable_a_col_2("test2");
tableA.setTable_a_col_3("test3");
tableA.setTable_a_col_4("test4");
System.out.println("Inserting data into first DB.");
tableARepository.save(tableA);
}
@GetMapping(path = "/addDataToSecondDB")
@Transactional("secondDBTransactionManager")
public @ResponseBody void addDataToSecondDB() {
// This returns a JSON or XML with the users
Table_C tableC = new Table_C();
tableC.setTable_c_col_1("test1");
tableC.setTable_c_col_2("test2");
tableC.setTable_c_col_3("test3");
tableC.setTable_c_col_4("test4");
System.out.println("Inserting data into second DB.");
tableCRepository.save(tableC);
}
}
Observe that, I've used @Transactional("secondDBTransactionManager") for second REST API, "addDataToSecondDB".
It is easy to resolve issue if any Exception is thrown. There is no Exception here but the behavior is not as expected.