How to add additional datasource?
There are multiple ways in OpenHub how to store custom business data.
See following variants:
a) Adding tables to the OpenHub schema
- is achievable via configuration
- JPA can be leveraged
- Nature & quantity of business data should be considered, as it cannot be scaled separately from the core tables
Steps
- Add custom JPA entities
- Extend OpenHub database scheme with new objects (tables, sequences ...) . Directly in project database, flyway in OpenHub can be used as well.
Configure EntityManager, to scan custom packages, with OpenHub configuration property ohf.jpa.additional-packages
Example:ohf.jpa.additional-packages=org.openhubframework.openhub.ri.persistence
- Entity manager bean can be used for building custom dao, or configure repositories using spring-data-jpa.
b) Add second datasource to be used without JPA
- straightforward setup, except that OpenHubDatasource is Primary bean, so project has to work with Qualified dataSource.
- For example JdbcTemplate can be used that way, other frameworks build on top if, or entirelly wrapped service (not exposing beans to spring context).
c) Add second datasource, with global transaction (one transactionManager)
- SpringBoot auto-configuration can be levered, either setup with JTA (Atomikos, Bitronix) or provided by application server.
- Project specific dataSource, entityManagerFactory (and entityManager) can be configured, to have two separate JPA contexts.
- Different databases can be configured for each JPA context as well.
Steps
- Add custom JPA entities.
- Configure project-specific DataSource & EntityManagerFactory. Each of them should have custom Qualifier.
Create custom dao, or configure spring-data-jpa repositories.
Configuration of spring-data-jpa repositories can look like this:@EnableJpaRepositories( entityManagerFactoryRef = "customEntityManagerFactory", basePackages = "org.openhubframework.openhub.ri.persistence.repository") @Configuration public class SecondDataSourceConfiguration { @Bean @Qualifier("customEntityManagerFactory") LocalContainerEntityManagerFactoryBean customEntityManagerFactory() { HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter(); jpaVendorAdapter.setGenerateDdl(false); LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean(); factoryBean.setJpaVendorAdapter(jpaVendorAdapter); factoryBean.setPackagesToScan(User.class.getPackage().getName()); factoryBean.setJtaDataSource(customDataSource()); return factoryBean; } @Bean @Qualifier("customDataSource") DataSource customDataSource() { return DataSourceBuilder.create() .url("jdbc:mysql://localhost:3306/testdb?useSSL=false&nullNamePatternMatchesAll=true") .driverClassName("com.mysql.jdbc.Driver") .username("*****") .password("*****") .build(); }
d) Add second datasource, each having its own transactionManager
- Spring boot by default does not configure transactionManager, if there is already bean present.
- OpenHub can be configured to provide its own JpaTransactionManager explicitely, even if there is already another bean of PlatformTransactionManager, see configuration property ohf.jpa.transaction-manager.enabled
Steps
- Add custom JPA entities.
- Configure project-specific DataSource, EntityManagerFactory & TransactionManager. Each of them should have custom Qualifier.
Configure OpenHub to register JpaTransactionManager for OpenHub entities. By default, it is disabled, and transactionManager is configured by SpringBoot.
ohf.jpa.transaction-manager.enabled=true
- Create custom dao, or configure spring-data-jpa repositories.
Configuration of spring-data-jpa repositories can look like this :
@EnableJpaRepositories( entityManagerFactoryRef = "customEntityManagerFactory", transactionManagerRef = "customTransactionManager", basePackages = "org.openhubframework.openhub.ri.persistence.repository") @Configuration public class SecondDataSourceJpaConfiguration { @Bean @Qualifier("customTransactionManager") PlatformTransactionManager customTransactionManager() { return new JpaTransactionManager(customEntityManagerFactory().getObject()); } @Bean @Qualifier("customEntityManagerFactory") LocalContainerEntityManagerFactoryBean customEntityManagerFactory() { HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter(); jpaVendorAdapter.setGenerateDdl(false); LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean(); factoryBean.setJpaVendorAdapter(jpaVendorAdapter); factoryBean.setPackagesToScan(User.class.getPackage().getName()); factoryBean.setDataSource(customDataSource()); return factoryBean; } @Bean @Qualifier("customDataSource") DataSource customDataSource() { return DataSourceBuilder.create() .url("jdbc:mysql://localhost:3306/testdb?useSSL=false&nullNamePatternMatchesAll=true") .driverClassName("com.mysql.jdbc.Driver") .username("*****") .password("*****") .build(); }