Autowire repositories from similar tables in different datasources - spring-boot

I have two versions of the same application. They are using similar database schemas. I want to run a junit test that compares two tables on both sides. I am using Springboot and JPA. I can autowire both datasources in the same test. I can autowire a CrudRepository for one of the tables in the primary datasource. But how can I autowire a similar repository for the same table that is sitting on the second datasource, at the same time in the same Junit test? I would like to do something like this on the same class:
#Autowired( Datasource="primarydatasource")
CustomerRepository fistCustomerRepository;
#Autowired( Datasource="seconddatasource")
CustomerRepository secondCustomerRepository;
I have checked many tutorials and answers here, but I have not found a clear example on this.

Using multiple datasources with Spring Boot

You can create two EntityManager
#Bean("em1")
public LocalContainerEntityManagerFactoryBean em1(
EntityManagerFactoryBuilder builder) {
return builder
.dataSource(customDataSource1())
.packages(DataSource.class)
.build();
}
#Bean("em2")
public LocalContainerEntityManagerFactoryBean em2(
EntityManagerFactoryBuilder builder) {
return ...;
}
Then you can inject the entity manager in you repository
#Repository
class CustomerRepositoryOracle{
#PersistenceContext(name="em1")
private EntityManager entityManager;
}
#Repository
class CustomerRepositoryPostgreSQL{
#PersistenceContext(name="em2")
private EntityManager entityManager;
}

Related

SpringBoot 3 native compilation not generating bean definition for second JpaRepository and failing to start with -Dspring.aot.enabled=true

I am facing an issue with Spring Boot 3 native compilation where the project contains two JpaRepository connecting to two different datasources. The creation of the second datasource configuration depends on the first datasource and JpaRepository as it contains the details about the databases to connect.
The problem is that the Spring Boot Maven plugin process-aot goal does not generate bean definition for repositories which are processed later on. As a result, the application fails to start with the -Dspring.aot.enabled=true property enabled.
I have tried several solutions, including:
Adding the #DependsOn annotation to the second datasource configuration class, but it didn't work.
Adding the #DependsOn annotation to the second JpaRepository, but it also didn't work.
Adding a #Configuration class that contains both datasource configurations, but it also didn't work.
Here is a simplified version of my code:
package com.company.multidatabases.config
#Configuration
public class DataSource1Config {
// datasource1 configuration
#Autowired
private MyEntity1Repository repo;
private Map<Object,Object> dataSources;
}
package com.company.config
#Configuration
public class DataSource2Config {
#Autowired
private DataSource1Config dataSource1Config;
#Bean
public DataSource dataSource(){
return // AbstractDataSourceRouting with datasources map from DataSource1Config
}
// datasource2 configuration that depends on dataSource1Config
}
package com.company.multidatabases.repository
#Repository
public interface MyEntity1Repository extends JpaRepository<MyEntity1, Long> {
// MyEntity1Repository definition
}
package com.company.repository
#Repository
public interface MyEntity2Repository extends JpaRepository<MyEntity2, Long> {
// MyEntity2Repository definition that depends on DataSource2Config
}
And here is the error message I get:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'myEntity1Repository' available
Any help or suggestion is highly appreciated. Thank you in advance.

Spring - Data persisted by JdbcTemplate unable to be seen by JpaRepository

I am building a Spring Boot application which requires the need for persistence via JDBC and selecting/reading via JPA/Hibernate. I have implemented both of these types of operations using Spring's JdbcTemplate and Spring Data's JpaRepository.
After I persist using JdbcTemplate I am unable to see the data via JpaRepository even though they share the same datasource. I am able to read the data if I use JdbcTemplate.
NOTE: I am using two data sources. One is configured in another class without the #Primary annotation using its own entity manager factory and transaction manager, which is why I've needed to explicitly define it below using Spring Boot's default bean terminology "transactionManager" and "entityManagerFactory".
The following is my embedded database configuration for the primary beans:
#Configuration
#EnableJpaRepositories(basePackages = {"com.repository"})
public class H2DataSourceConfiguration {
private static final Logger log = LoggerFactory.getLogger(H2DataSourceConfiguration.class);
#Bean(destroyMethod = "shutdown")
#Primary
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.setName("dataSource")
.build();
}
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder, DataSource dataSource) {
return builder
.dataSource(dataSource)
.packages("com.my.domain", "org.springframework.data.jpa.convert.threeten")
.build();
}
#Bean
#Primary
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager(entityManagerFactory);
return jpaTransactionManager;
}
}
The persistence happens in a different transaction to the reading of the data, however they share the same service.
Both operations happen within the #Transactional annotation. Both repository beans are specified in the same service and also contain the #Transactional annotation. The service looks as follows:
#Service
#Transactional
public class MyServiceImpl implements MyService {
private static final Logger log = LoggerFactory.getLogger(MyServiceImpl.class);
#Autowired
private MyJpaRepository myJpaRepository;
#Autowired
private MyJdbcRepository myJdbcRepository;
...
}
MyJdbcRepositoryImpl.java:
#Repository
#Transactional(propagation = Propagataion.MANDATORY)
public class MyJdbcRepositoryImpl implements MyJdbcRepository {
#Autowired
private NamedParameterJdbcTemplate jdbcTemplate;
// methods within here all use jdbcTemplate.query(...)
}
MyJpaRepository.java:
#Repository
#Transactional(propagation = Propagataion.MANDATORY)
public interface AcquisitionJpaRepository extends JpaRepository<AcquisitionEntity, Long> {
}
Is it at all possible that the jdbctemplate calls are saving to a different h2 database?
The above configuration is correct!
The problem was that the JdbcTemplate calls had the schema owner as a prefix.
For example:
select * from I_AM_SCHEMA.KILL_ME
However, I had both the #Entity annotation and the #Table annotation on the entity object and only specified the table name!
Example:
#Entity
#Table(name = "KILL_ME")
So, we were writing to one table with JdbcTemplate but reading from a completely different other table via JPA/Hibernate due to us missing the prefix.
The correct fix was to prefix the entity name in the #Entity annotation:
#Entity("I_AM_SCHEMA.KILL_ME")
DONE!

Spring + multiple H2 instances in memory

Two different H2 instances to be created in-memory. To make sure this happens, I initialized both instances with same shema and different data. So that when I query using DAO different set of data picked from different DataSource. However this is not happening. What am I doing wrong? How to name the instance of H2 correct?
#Bean(name = "DS1")
#Primary
public EmbeddedDatabase dataSource1() {
return new EmbeddedDatabaseBuilder().
setType(EmbeddedDatabaseType.H2).
setName("DB1").
addScript("schema.sql").
addScript("data-1.sql").
build();
}
#Bean(name = "DS2")
public EmbeddedDatabase dataSource2() {
return new EmbeddedDatabaseBuilder().
setType(EmbeddedDatabaseType.H2).
setName("DB2").
addScript("schema.sql").
addScript("data-2.sql").
build();
}
You have created two DataSources and have marked one as #Primary -- this is the one which will be used when your EntityManagerFactories and Repositories are autoconfigured. That's why both DAO's are accessing the same database.
In order to get around this, you need to declare two separate EntityManagerFactories, as described in the Spring Boot documentation:
http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#howto-use-two-entity-managers
After that, you'll need to declare two separate repositories and tell each repository which of the EntityManagerFactory to use. To do this, in your #EnableJpaRepositories annotation you'll have to specify the correct EntityMangerFactory. This article describes very nicely how to do that:
http://scattercode.co.uk/2013/11/18/spring-data-multiple-databases/
It would be nice if Spring Boot supported autoconfiguration with two DataSources, but I don't think it's going to happen soon:
https://github.com/spring-projects/spring-boot/issues/808
UPDATE
The author of the above article has published an updated approach:
https://scattercode.co.uk/2016/01/05/multiple-databases-with-spring-boot-and-spring-data-jpa/
The issue was not with multiple instances of H2; but with DataSource injection.
I solved it by passing the Qualifier in method argument.
#Autowired
#Bean(name = "jdbcTemplate")
public JdbcTemplate getJdbcTemplate(#Qualifier("myDataSource") DataSource dataSource) {
return new JdbcTemplate(dataSource);
}

Spring 4 Using #Lazy and #Resource annotations together

I would like to lazy load a resource within a lazy loaded configuration class. it seems that it is not currently possible with Spring 4.1.
#Configuration
#Lazy
public class ModificationConfiguration {
#Resource(name="modProps")
#Lazy
Map<String, String> props;
#Bean
Map<String, String> modProps(){
...
}
}
from the Spring documentation
In addition to its role for component initialization, the #Lazy annotation may also be placed on
injection points marked with #Autowired or #Inject. In this context, it leads to the injection
of a lazy-resolution proxy.
It seems natural to also want this available with #Resource as I can't use #Autowired on a Map<String, String>. Without the #Lazy being available on #Resource the modProps() bean is created straight away.
Is there a technical reason why it is not currently possible to do this?

JPA's EntityManager or Hibernate's HibernateTemplate with Spring

I have decided to use Spring, Hibernate, and Restlet to create a web service. I am new to all of these three technologies. My question is this: How do I decide whether to use JPA's EntityManager or Hibernate's HibernateTemplate?
Code snippet for JPA's EntityManager:
protected EntityManager entityManager;
#PersistenceContext
public void setEngityManager(EntityManager entityManger) {
this.entityManager = entityManager;
}
Code snippet for Hibernate's HibernateTemplate:
private SessionFactory sessionFactory;
private HibernateTemplate hibernateTemplate;
#Autowired
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
this.hibernateTemplate = new HibernateTemplate(sessionFactory);
}
If you are someone who like interface-based-implementation, then JPA is the interface definition and Hibernate is one of the implementations. We decided to use JPA semantics in our project (with a very long term plan to replace Hibernate with something similar and light-weight probably).
If you want to stick to hibernate in future, then no point in using EntityManagerFactory, you can go ahead and use SessionFactory. And just inject definition for this using java based configuration or xml. It must be available in application context.
But in future if you might want to move to different jpa provider, like toplink etc, then you should use EntityManagerFactory as it allows you to have implementation from various provider. Because providers implement jpa specification. So in future you just need to have different configuration in your application context and you should be able to use that.

Resources