Spring Boot + Camel JPA with multiple Datasources - spring-boot

I need to create a Camel route that polls a DB, transforms the retrieved data and then inserts the new entities into another DB. I need help with the configuration.
These are the jpa endpoints:
from("jpa://" + Entity1.class.getName()
+ "?"
+ "persistenceUnit=entity1PU&"
+ "consumer.namedQuery=query1&"
+ "consumeDelete=false"
)
//various operations...
.to("direct:route2");
from("direct:route2")
.process(new Processor() {
public void process(Exchange exchange) throws Exception {
//processing...
}
})
.to("jpa://" + Entity2.class.getName()
+ "?"
+ "persistenceUnit=entity2PU&"
+ "entityType=java.util.ArrayList&"
+ "usePersist=true&"
+ "flushOnSend=true");
I'd like to configure the persistence units by code and annotations, instead of using persistence.xml; these are the relative classes. This is the first:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
basePackages = "com.foo.entity1.repo",
entityManagerFactoryRef = "entity1EntityManagerFactory",
transactionManagerRef = "entity1TransactionManager"
)
public class Entity1PersistenceConfig {
#Autowired
#Qualifier("datasource1")
private DataSource dataSource;
#Primary
public DataSource dataSource() {
return this.dataSource;
}
#Primary
#Bean(name="entity1EntityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("com.foo.entity1.domain");
factory.setDataSource(this.dataSource());
factory.setPersistenceProviderClass(HibernatePersistenceProvider.class);
factory.setPersistenceUnitName("entity1PU");
Properties hibernateProps = setJpaHibernateCommonProperties();
hibernateProps.setProperty("hibernate.dialect", environment.getProperty("spring.jpa.properties.hibernate.oracle.dialect"));
factory.setJpaProperties(hibernateProps);
return factory;
}
#Primary
#Bean(name="entity1TransactionManager")
public PlatformTransactionManager transactionManager() {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return jpaTransactionManager;
}
}
and the second one:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
basePackages = "com.foo.entity2.repo",
entityManagerFactoryRef = "entity2EntityManagerFactory",
transactionManagerRef = "entity2TransactionManager"
)
public class Entity2PersistenceConfig {
#Autowired
#Qualifier("datasource2")
private DataSource dataSource;
public DataSource dataSource() {
return this.dataSource;
}
#Bean(name="entity2EntityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("com.foo.entity2.domain");
factory.setDataSource(this.dataSource());
factory.setPersistenceProviderClass(HibernatePersistenceProvider.class);
factory.setPersistenceUnitName("entity2PU");
Properties hibernateProps = setJpaHibernateCommonProperties();
hibernateProps.setProperty("hibernate.dialect", environment.getProperty("spring.jpa.properties.hibernate.mysql.dialect"));
factory.setJpaProperties(hibernateProps);
return factory;
}
#Bean(name="entity2TransactionManager")
public PlatformTransactionManager transactionManager() {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return jpaTransactionManager;
}
}
Entities and repositories are in the correct packages; also, the configuration of the databases is correctly done in a specific class, and are correctly injected.
When I try to run the project, I get the following:
2018-05-30 11:38:36.481 INFO 1056 --- [main] o.h.j.b.internal.PersistenceXmlParser: HHH000318: Could not find any META-INF/persistence.xml file in the classpath
and
javax.persistence.PersistenceException: No Persistence provider for EntityManager named entity1PU
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:61) ~[hibernate-jpa-2.1-api-1.0.0.Final.jar:1.0.0.Final]
at org.springframework.orm.jpa.LocalEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalEntityManagerFactoryBean.java:96) ~[spring-orm-4.3.17.RELEASE.jar:4.3.17.RELEASE]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:384) ~[spring-orm-4.3.17.RELEASE.jar:4.3.17.RELEASE]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:371) ~[spring-orm-4.3.17.RELEASE.jar:4.3.17.RELEASE]
at org.apache.camel.component.jpa.JpaEndpoint.createEntityManagerFactory(JpaEndpoint.java:552) ~[camel-jpa-2.21.1.jar:2.21.1]
at org.apache.camel.component.jpa.JpaEndpoint.getEntityManagerFactory(JpaEndpoint.java:250) ~[camel-jpa-2.21.1.jar:2.21.1]
at org.apache.camel.component.jpa.JpaEndpoint.validate(JpaEndpoint.java:545) ~[camel-jpa-2.21.1.jar:2.21.1]
at org.apache.camel.component.jpa.JpaEndpoint.createConsumer(JpaEndpoint.java:165) ~[camel-jpa-2.21.1.jar:2.21.1]
at org.apache.camel.impl.EventDrivenConsumerRoute.addServices(EventDrivenConsumerRoute.java:69) ~[camel-core-2.21.1.jar:2.21.1]
at org.apache.camel.impl.DefaultRoute.onStartingServices(DefaultRoute.java:103) ~[camel-core-2.21.1.jar:2.21.1]
at org.apache.camel.impl.RouteService.doWarmUp(RouteService.java:172) ~[camel-core-2.21.1.jar:2.21.1]
at org.apache.camel.impl.RouteService.warmUp(RouteService.java:145) ~[camel-core-2.21.1.jar:2.21.1]
Why is it looking for a persistence.xml file instead of using annotations? I'm using Spring Boot 1.5.13.RELEASE with Camel 2.21.1.

Basically to make it work I had to abandon using annotations and create an equivalent persistence.xml file, because Apache Camel was looking for configuration only in it.
As soon as I could upgrade to Spring Boot 2 (because Apache Camel got updated and started to support it), I managed to make configuration by annotations work and dropped the persistence.xml file.

Related

How to use a second data source in spring?

I downloaded the example code here
https://github.com/spring-projects/spring-data-examples/tree/master/jpa/multiple-datasources
but I still don't understand how an repository is connected to a datasource. Even when I look into the config class, it makes no reference to a repository. And inside the repository interface it makes no reference to the data source or config.
So when you use two different repositories to save, how does it know which datasource to go to for each repo?
In the repository with examples you linked, each config class is annotated with #EnableJpaRepositories that does scanning for repositories only in the package of annotated class plus subpackages - this is where the relation between datasource and repository happens.
Notice the configurations (commented as /* important */)
in OrderConfig
#Configuration
/* important */
#EnableJpaRepositories(entityManagerFactoryRef = "orderEntityManagerFactory",
transactionManagerRef = "orderTransactionManager")
class OrderConfig {
#Bean
PlatformTransactionManager orderTransactionManager() {
return new JpaTransactionManager(orderEntityManagerFactory().getObject());
}
#Bean
LocalContainerEntityManagerFactoryBean orderEntityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
/* important */
factoryBean.setDataSource(orderDataSource());
factoryBean.setJpaVendorAdapter(vendorAdapter);
factoryBean.setPackagesToScan(OrderConfig.class.getPackage().getName());
return factoryBean;
}
#Bean
DataSource orderDataSource() {
return new EmbeddedDatabaseBuilder().//
setType(EmbeddedDatabaseType.HSQL).//
setName("orders").//
build();
}
}
and, CustomerConfig
#Configuration
/* important */
#EnableJpaRepositories(entityManagerFactoryRef = "customerEntityManagerFactory",
transactionManagerRef = "customerTransactionManager")
class CustomerConfig {
#Bean
PlatformTransactionManager customerTransactionManager() {
return new JpaTransactionManager(customerEntityManagerFactory().getObject());
}
#Bean
LocalContainerEntityManagerFactoryBean customerEntityManagerFactory() {
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
jpaVendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
/* important */
factoryBean.setDataSource(customerDataSource());
factoryBean.setJpaVendorAdapter(jpaVendorAdapter);
factoryBean.setPackagesToScan(CustomerConfig.class.getPackage().getName());
return factoryBean;
}
#Bean
DataSource customerDataSource() {
return new EmbeddedDatabaseBuilder().//
setType(EmbeddedDatabaseType.HSQL).//
setName("customers").//
build();
}
}
and, finally the #Transactional annotation in DataInitializer
/* important */
#Transactional("customerTransactionManager")
public CustomerId initializeCustomer() {
return customers.save(new Customer("Dave", "Matthews")).getId();
}
uses customerTransactionManager which is configured in CustomerConfig
and,
/* important */
#Transactional("orderTransactionManager")
public Order initializeOrder(CustomerId customer) {
Assert.notNull(customer, "Customer identifier must not be null!");
Order order = new Order(customer);
order.add(new LineItem("Lakewood Guitar"));
return orders.save(order);
}
uses orderTransactionManager which is configured in OrderConfig
Basically, you're configuring different datasources, different entityManagers, different transactionManagers and refer to them specifically as per your choice.

Spring Boot Dual data configuration, unable to reconnect after connection lost

I am working on application written in spring Boot 1.5.3. I have two data source which are configured as below.
Main connection
spring.datasource.driverClassName = org.postgresql.Driver
spring.datasource.url = jdbc:postgresql://xxx.xxx.xxx.xx:5432/mydb
spring.datasource.username = xxxx
spring.datasource.password = xxxx
spring.jpa.properties.hibernate.default_schema=test
# Number of ms to wait before throwing an exception if no connection is available.
spring.datasource.tomcat.max-wait=10000
# Maximum number of active connections that can be allocated from this pool at the same time.
spring.datasource.tomcat.max-active=150
spring.datasource.tomcat.max-idle=30
spring.datasource.tomcat.min-idle=2
spring.datasource.tomcat.initial-size=3
# Validate the connection before borrowing it from the pool.
spring.datasource.tomcat.test-on-borrow=true
spring.datasource.tomcat.test-on-connect=true
spring.datasource.time-between-eviction-runs-millis=60000
#spring.datasource.tomcat.validation-query-timeout=1000
spring.datasource.tomcat.validation-query=SELECT 1
spring.datasource.tomcat.validation-interval=1000
spring.datasource.tomcat.remove-abandoned=true
spring.datasource.tomcat.remove-abandoned-timeout=55
spring.datasource.tomcat.test-while-idle=true
spring.datasource.tomcat.min-evictable-idle-time-millis = 55000
spring.datasource.tomcat.time-between-eviction-runs-millis = 34000
Second Connection
spring.rdatasource.driverClassName = org.postgresql.Driver
spring.rdatasource.url = jdbc:postgresql://xxx.xxx.xxx.xx:5432/mydb1
spring.rdatasource.username = xxxx
spring.rdatasource.password = xxxx
spring.jpa.properties.hibernate.default_schema=test
# Number of ms to wait before throwing an exception if no connection is available.
spring.rdatasource.tomcat.max-wait=10000
# Maximum number of active connections that can be allocated from this pool at the same time.
spring.rdatasource.tomcat.max-active=150
spring.rdatasource.tomcat.max-idle=30
spring.rdatasource.tomcat.min-idle=2
spring.rdatasource.tomcat.initial-size=3
# Validate the connection before borrowing it from the pool.
spring.rdatasource.tomcat.test-on-borrow=true
spring.rdatasource.tomcat.test-on-connect=true
spring.rdatasource.time-between-eviction-runs-millis=60000
#spring.rdatasource.tomcat.validation-query-timeout=1000
spring.rdatasource.tomcat.validation-query=SELECT 1
spring.rdatasource.tomcat.validation-interval=1000
spring.rdatasource.tomcat.remove-abandoned=true
spring.rdatasource.tomcat.remove-abandoned-timeout=55
spring.rdatasource.tomcat.test-while-idle=true
spring.rdatasource.tomcat.min-evictable-idle-time-millis = 55000
spring.rdatasource.tomcat.time-between-eviction-runs-millis = 34000
I am working in in VPN environment. When I run application, application is working fine. But the issue starts when I disconnect the VPN and reconnect the VPN.again, my application won't reconnect to data source again. Instead I always getting exception.
But working single database when leave connection handling to spring itself and I do not perform any database configuration.
Update
#Configuration
#PropertySource({ "classpath:application.properties" })
#EnableJpaRepositories(
basePackages = {"com.services.persistence"},
entityManagerFactoryRef = "entityManager",
transactionManagerRef = "transactionManager"
)
#ComponentScan("com.services.persistence")
#EnableTransactionManagement
public class DBConfig {
#Autowired private Environment env;
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean entityManager() {
LocalContainerEntityManagerFactoryBean em
= new LocalContainerEntityManagerFactoryBean();
em.setDataSource(userDataSource());
em.setPackagesToScan(
new String[] { "com.services.persistence", "com.services.persistence.pojo" });
HibernateJpaVendorAdapter vendorAdapter
= new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
// properties.put("hibernate.hbm2ddl.auto",
// env.getProperty("hibernate.hbm2ddl.auto"));
properties.put("hibernate.dialect",
env.getProperty("spring.jpa.database-platform"));
properties.put("hibernate.current_session_context_class",
env.getProperty("spring.jpa.properties.hibernate.current_session_context_class"));
em.setJpaPropertyMap(properties);
return em;
}
#Primary
#Bean
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource userDataSource() {
return DataSourceBuilder
.create()
.build();
}
#Primary
#Bean
public JpaTransactionManager transactionManager() {
JpaTransactionManager transactionManager
= new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
entityManager().getObject());
return transactionManager;
}
#Bean(name = "sessionFactory")
public SessionFactory getSessionFactory() {
SessionFactory sessionFactory = transactionManager().getEntityManagerFactory().unwrap(SessionFactory.class);
if (sessionFactory == null) {
throw new NullPointerException("factory is not a hibernate factory");
} else {
System.out.println(
"==================================== Transaction Enabled ========================================");
return sessionFactory;
}
}
I have also configured spring.rdatasource and it is same as above file, except it is not set as primary and other further details like pojo, transactionmanager etc.

spring batch not rolling on runtime exception in itemwriter

I am new to spring batch and I have a spring batch with spring data project with oracle database. Basically for simplicity I have 2 steps :
Step 1 : Read the first row of the csv file than insert in table_header in itemwriter
Step 2 : Read from the second row of the csv file than insert in table_detail in itemwriter.
The table_header is linked to table_detail - one to many relationship.
Basically if a runtime exception in triggered in step 2 just after saving the detail while in the same step the data does not roll back.According to spring reference it should roll back on runtime exception.
I am not sure what i am missing in order for the transaction to rollback, can someone point me to the right direction pls?
Please find below my database configuration:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(entityManagerFactoryRef = "dummyEntityManager", transactionManagerRef = "dummyTransactionManager", basePackages = {
"com.dummy.persistence" })
#PropertySource("file:${test_PROPERTIES}")
public class DatabaseConfig extends HikariConfig {
#Bean(name = "dummyDatasource")
public HikariDataSource dataSource() {
HikariDataSource hikariDataSource = new HikariDataSource();
hikariDataSource.setJdbcUrl(CipherWrapper.getInstance().decrypt(jdbcUrl));
hikariDataSource.setUsername(CipherWrapper.getInstance().decrypt(username));
hikariDataSource.setPassword(CipherWrapper.getInstance().decrypt(password));
hikariDataSource.setAutoCommit(false);
hikariDataSource.setMaximumPoolSize(maximumPoolSize);
hikariDataSource.setMinimumIdle(minimumIdle);
return hikariDataSource;
}
#Bean(name = "dummyEntityManager")
public LocalContainerEntityManagerFactoryBean dummyEntityManagerFactory(EntityManagerFactoryBuilder builder) {
LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean = builder.dataSource(dataSource())
.packages("com.dummy.persistence.entity").persistenceUnit("dummyPersistenceUnit").build();
localContainerEntityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
return localContainerEntityManagerFactoryBean;
}
#Bean(name = "dummyTransactionManager")
public PlatformTransactionManager dummyTransactionManager(
#Qualifier("dummyEntityManager") EntityManagerFactory dummyEntityManagerFactory) {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager(dummyEntityManagerFactory);
jpaTransactionManager.setRollbackOnCommitFailure(true);
return jpaTransactionManager;
}
#Bean
public BatchConfigurer batchConfigurer(#Qualifier("dummyEntityManager") EntityManagerFactory dummyEntityManagerFactory) {
return new DefaultBatchConfigurer() {
#Override
public PlatformTransactionManager getTransactionManager() {
return dummyTransactionManager(dummyTransactionManager);
}
};
}
}
Please find below both step config:
#Bean("step1")
public Step headerSaveStep() {
StepBuilder stepBuilder = stepBuilderFactory.get(Flow.STEP1.toString());
SimpleStepBuilder<HeaderDetailsDto,HeaderDetailsAdditionaDto> simpleStepBuilder = stepBuilder
.<HeaderDetailsDto, HeaderDetailsAdditionaDto>chunk(1);
simpleStepBuilder.reader(csvItemReader.csvFileVatPayerDetailsItemReader(null));
simpleStepBuilder.processor(EnrichmentProcessor());
simpleStepBuilder.writer(headerWriter());
simpleStepBuilder.allowStartIfComplete(true);
return simpleStepBuilder.build();
}
#Bean("step2")
public Step detailSaveStep() {
StepBuilder stepBuilder = stepBuilderFactory.get(Flow.STEP2.toString());
SimpleStepBuilder<DetailsDto, DetailsDto> simpleStepBuilder = stepBuilder
.<DetailsDto, DetailsDto>chunk(20000);
simpleStepBuilder.reader(csvItemReader.csvFileBuyerDetailsFileItemReader(null));
simpleStepBuilder.writer(detailsWriter());
simpleStepBuilder.allowStartIfComplete(true);
return simpleStepBuilder.build();
}
Your transaction manager is not being used by Spring Batch. You need to define a BatchConfigurer bean referring to it (See example here). Hope this helps.

Spring Data JPA - Multiple EnableJpaRepositories

My application has multiple data sources , so i have created two data source configuration classes based on this URL .
But while running the spring boot application am getting error
Description:
Field userDataRepo in com.cavion.services.UserDataService required a bean named 'entityManagerFactory' that could not be found.
Action:
Consider defining a bean named 'entityManagerFactory' in your configuration.
From this Question on StackOverflow helped me to figure out the issue.i need to specify the entityManagerFactoryRef on my JPA repositories .
But i have many repository classes some of them uses Entitymanager 'A' and some of them uses 'B' . my current spring boot application class is like this
#SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class })
#EnableTransactionManagement
#EntityScan("com.info.entity")
#ComponentScan({"com.info.services","com.info.restcontroller"})
#EnableJpaRepositories("com.info.repositories")
public class CavionApplication {
public static void main(String[] args) {
SpringApplication.run(CavionApplication.class, args);
}
#Bean
public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
return args -> {
System.out.println("Let's inspect the beans provided by Spring Boot:");
String[] beanNames = ctx.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
System.out.println(beanName);
}
};
}}
I have given the EnableJpaRepositories on the spring boot class , so how can i configure multiple EnableJpaRepositories so that i can configure multiple entityManagerFactory ?
Please suggest the best way to setup the multiple data sources .
In order to let spring knows what DataSource is related to what Repository you should define it at the #EnableJpaRepositories annotation. Let's assume that we have two entities, the Servers entity and the Domains entity and each one has its own Repo then each Repository has its own JpaDataSource configuration.
1. Group all the repositories based on the Data Source that they are related to. For example
Repository for Domains entities (package: org.springdemo.multiple.datasources.repository.domains):
package org.springdemo.multiple.datasources.repository.domains;
import org.springdemo.multiple.datasources.domain.domains.Domains;
import org.springframework.data.jpa.repository.JpaRepository;
public interface DomainsRepository extends JpaRepository<Domains,Long> {
}
Repository for Servers entities (package: org.springdemo.multiple.datasources.repository.servers)
package org.springdemo.multiple.datasources.repository.servers;
import org.springdemo.multiple.datasources.domain.servers.Servers;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ServersRepository extends JpaRepository<Servers,Long> {
}
2. For each JPA Data Soruce you need to define a configuration, in this example I show how to configure two different DataSources
Domains Jpa Configuration: the relationship between the Data Source and the repository is defined in the basePackages value, that is the reason why is necessary to group the repositories in different packages depending on the entity manager that each repo will use.
#Configuration
#EnableJpaRepositories(
entityManagerFactoryRef = "domainsEntityManager",
transactionManagerRef = "domainsTransactionManager",
basePackages = {"org.springdemo.multiple.datasources.repository.domains"}
)
public class DomainsConfig {
Servers Data Source Configuration: as you can see the basePackages value has the package name of the Servers Repository , and also the values of entityManagerFactoryRef and transactionManagerRef are different in order to let spring separate each entityManager.
#Configuration
#EnableJpaRepositories(
entityManagerFactoryRef = "serversEntityManager",
transactionManagerRef = "serversTransactionManager",
basePackages = {"org.springdemo.multiple.datasources.repository.servers"}
)
public class ServersConfig {
3. Set one Datasource as primary
In order to avoid the error message: Parameter 0 of constructor in org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration required a single bean, but 2 were found: just set one of the datasource as #Primary, in this example I select the Servers Datasource as primary:
#Bean("serversDataSourceProperties")
#Primary
#ConfigurationProperties("app.datasource.servers")
public DataSourceProperties serversDataSourceProperties(){
return new DataSourceProperties();
}
#Bean("serversDataSource")
#Primary
#ConfigurationProperties("app.datasource.servers")
public DataSource serversDataSource(#Qualifier("serversDataSourceProperties") DataSourceProperties serversDataSourceProperties) {
return serversDataSourceProperties().initializeDataSourceBuilder().build();
}
If you need more information please see the full example for each configuration:
Servers JPA Configuration
#Configuration
#EnableJpaRepositories(
entityManagerFactoryRef = "serversEntityManager",
transactionManagerRef = "serversTransactionManager",
basePackages = {"org.springdemo.multiple.datasources.repository.servers"}
)
public class ServersConfig {
#Bean(name = "serversEntityManager")
public LocalContainerEntityManagerFactoryBean getServersEntityManager(EntityManagerFactoryBuilder builder,
#Qualifier("serversDataSource") DataSource serversDataSource){
return builder
.dataSource(serversDataSource)
.packages("org.springdemo.multiple.datasources.domain.servers")
.persistenceUnit("servers")
.properties(additionalJpaProperties())
.build();
}
Map<String,?> additionalJpaProperties(){
Map<String,String> map = new HashMap<>();
map.put("hibernate.hbm2ddl.auto", "create");
map.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
map.put("hibernate.show_sql", "true");
return map;
}
#Bean("serversDataSourceProperties")
#Primary
#ConfigurationProperties("app.datasource.servers")
public DataSourceProperties serversDataSourceProperties(){
return new DataSourceProperties();
}
#Bean("serversDataSource")
#Primary
#ConfigurationProperties("app.datasource.servers")
public DataSource serversDataSource(#Qualifier("serversDataSourceProperties") DataSourceProperties serversDataSourceProperties) {
return serversDataSourceProperties().initializeDataSourceBuilder().build();
}
#Bean(name = "serversTransactionManager")
public JpaTransactionManager transactionManager(#Qualifier("serversEntityManager") EntityManagerFactory serversEntityManager){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(serversEntityManager);
return transactionManager;
}
}
Domains JPA Configuration
#Configuration
#EnableJpaRepositories(
entityManagerFactoryRef = "domainsEntityManager",
transactionManagerRef = "domainsTransactionManager",
basePackages = {"org.springdemo.multiple.datasources.repository.domains"}
)
public class DomainsConfig {
#Bean(name = "domainsEntityManager")
public LocalContainerEntityManagerFactoryBean getdomainsEntityManager(EntityManagerFactoryBuilder builder
,#Qualifier("domainsDataSource") DataSource domainsDataSource){
return builder
.dataSource(domainsDataSource)
.packages("org.springdemo.multiple.datasources.domain.domains")
.persistenceUnit("domains")
.properties(additionalJpaProperties())
.build();
}
Map<String,?> additionalJpaProperties(){
Map<String,String> map = new HashMap<>();
map.put("hibernate.hbm2ddl.auto", "create");
map.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
map.put("hibernate.show_sql", "true");
return map;
}
#Bean("domainsDataSourceProperties")
#ConfigurationProperties("app.datasource.domains")
public DataSourceProperties domainsDataSourceProperties(){
return new DataSourceProperties();
}
#Bean("domainsDataSource")
public DataSource domainsDataSource(#Qualifier("domainsDataSourceProperties") DataSourceProperties domainsDataSourceProperties) {
return domainsDataSourceProperties.initializeDataSourceBuilder().build();
}
#Bean(name = "domainsTransactionManager")
public JpaTransactionManager transactionManager(#Qualifier("domainsEntityManager") EntityManagerFactory domainsEntityManager){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(domainsEntityManager);
return transactionManager;
}
}
In order to separate each datasource I put the configuration in the application.properties file, like this:
app.datasource.domains.url=jdbc:h2:mem:~/test
app.datasource.domains.driver-class-name=org.h2.Driver
app.datasource.servers.driver-class-name=com.mysql.jdbc.Driver
app.datasource.servers.url=jdbc:mysql://localhost:3306/v?autoReconnect=true&useSSL=false
app.datasource.servers.username=myuser
app.datasource.servers.password=mypass
If you need more information please see the following documentation:
Spring Documentation: howto-two-datasources
A similar example of how configure two different databases: github example
The answered provided by #Daniel C. is correct. Small correction/observation from my side.
#Primary is not required if you don't want to mark any datasource as
default one, otherwise necessary.
If you are defining any of the EntityManagerFactoryBean with #Bean name as entityManagerFactory then it's better to mark it #Primary to avoid conflict.
#ConfigurationProperties("app.datasource.servers")
can be marked at class level instead of defining at method level.
Better to return HikariDataSource as datasource if you using Spring
Boot 2.x or higher version as it has been changed.
Make sure you define exact property for jdbc-url which is being used by
HikariDataSource to refer JDBC Connection URL.
I just added a module aware multi database aware library for mysql in github.Some application properties need to be added and you are done .
Documentation and other details could be found at :-
https://github.com/yatharthamishra0419/spring-boot-data-multimodule-mysql

How to define HSQ DB properties in Spring JPA using annoations

I am running HSQL DB as a Im memory using run manger Swing.I have to connect the HSQLDB server from Spring JPA repository using annotations.
My repository class.
#RepositoryRestResource
public interface Vehicle extends JpaRepository<Vehicle , BigInteger>{
public List<Vehicle > findAll(Sort sort);
}
service Method:
#Service
public class LocationService {
#Autowired
VehicletRepository vehicleRepository = null;
/**
* This method is to get all the locations from the repository
*/
public List<Vehicle> getVehicless() {
Order order = new Order(Direction.ASC,"vehicleCode");
Sort sort = new Sort(order);
List<Airport> airports = vehicletRepository .findAll(sort);
System.out.println("inside service");
return vehicles;
}
}
Anyone help to achieve Spring JPA conenction with HSQL DB using annotations.
I assume you dont use Spring boot:
you need #Configuration class -(it basically is new way to configure spring applications in java ) with #EnableJpaRepositories which turn it spring data jpa/ spring data rest for you. You will also have to specify your entity manager, transaction manager and data source beans. Example below:
#Configuration
#EnableJpaRepositories("your.package.with.repositories")
public class DBConfig{
#Bean
public JpaTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
#Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
DBConfigurationCommon.configureDB(dataSource, your_jdbc_url_here, db_username_here, db_password_here);
return dataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
//you may need to define new Properties(); here with hibernate dialect and add it to entity manager factory
entityManagerFactoryBean.setPackagesToScan("your_package_with_domain_classes_here");
return entityManagerFactoryBean;
}
}

Resources