Connection to two different databases in Spring JPA fails - spring

I am trying to use 2 different data sources/databases in my application but so far I am not able to connect to them.
FirstDb Config file
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = "xx.xx.xx.crud.repository.running", entityManagerFactoryRef = "dummyTestEntityManagerFactory", transactionManagerRef = "transactionManagerOne")
#PropertySource("classpath:application.properties")
public class dummyTestDbConfig {
#Value("${spring.datasourcedummyTestraid.driver-class-name}")
String driverClassName = "";
#Value("${spring.datasourcedummyTestraid.url}")
String url = "";
#Value("${spring.datasourcedummyTestraid.username}")
String userName = "";
#Value("${spring.datasourcedummyTestraid.password}")
String password = "";
#Autowired
#Qualifier("jpadummyTestVendorApapter")
JpaVendorAdapter jpadummyTestVendorApapter;
#Bean(name = "dummyTestDataSource")
#Primary
public DataSource dummyTestDataSource() {
return DataSourceBuilder.create().url(url)
.driverClassName(driverClassName).username(userName)
.password(password).build();
}
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean dummyTestEntityManagerFactory() {
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(dummyTestDataSource());
factoryBean.setJpaVendorAdapter(jpadummyTestVendorApapter);
factoryBean.setPackagesToScan(R.dummyTestDB_PACKAGE);
factoryBean.setPersistenceUnitName("dummyTestPersistenceUnit");
factoryBean.afterPropertiesSet();
return factoryBean;
}
#Bean
PlatformTransactionManager transactionManagerOne() {
return new JpaTransactionManager(dummyTestEntityManagerFactory()
.getObject());
}
#Bean(name = "jpadummyTestVendorApapter")
#Primary
public JpaVendorAdapter jpadummyTestVendorAdapter() {
HibernateJpaVendorAdapter jpadummyTestVendorAdapter = new HibernateJpaVendorAdapter();
jpadummyTestVendorAdapter.setShowSql(true);
jpadummyTestVendorAdapter.setGenerateDdl(true);
jpadummyTestVendorAdapter.setDatabase(Database.MYSQL);
return jpadummyTestVendorAdapter;
}
#Bean
public HibernateExceptionTranslator hibernateExceptionTranslator() {
return new HibernateExceptionTranslator();
}
}
Second db config
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = "xx.xx.xx.xx.xx.running", entityManagerFactoryRef = "alpharaidEntityManagerFactory", transactionManagerRef = "transactionManagertwo")
#PropertySource("classpath:application.properties")
public class alphaDbConfig {
#Value("${spring.datasourcealpharaid.driver-class-name}")
String driverClassName = "";
#Value("${spring.datasourcealpharaid.url}")
String url = "";
#Value("${spring.datasourcealpharaid.username}")
String userName = "";
#Value("${spring.datasourcealpharaid.password}")
String password = "";
#Autowired
#Qualifier("jpaMyalphaVendorAdapter")
JpaVendorAdapter myalphaVendorAdapter;
#Bean(name = "alpharaidDataSource")
public DataSource alpharaidDataSource() {
return DataSourceBuilder.create().url(url)
.driverClassName(driverClassName).username(userName)
.password(password).build();
}
#Bean
public LocalContainerEntityManagerFactoryBean alpharaidEntityManagerFactory() {
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(alpharaidDataSource());
factoryBean.setJpaVendorAdapter(myalphaVendorAdapter);
factoryBean.setPackagesToScan(R.alphaDB_PACKAGE);
factoryBean.setPersistenceUnitName("alpharaidPersistenceUnit");
factoryBean.afterPropertiesSet();
return factoryBean;
}
#Bean
PlatformTransactionManager transactionManagerTwo() {
return new JpaTransactionManager(alpharaidEntityManagerFactory()
.getObject());
}
#Bean(name = "jpaMyalphaVendorAdapter")
public JpaVendorAdapter jpaMyalphaVendorAdapter() {
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
jpaVendorAdapter.setShowSql(true);
jpaVendorAdapter.setGenerateDdl(true);
jpaVendorAdapter.setDatabase(Database.MYSQL);
return jpaVendorAdapter;
}
}
when i start server, i recieve Exception
2015-08-19 15:21:25.412 ERROR 16928 --- [ main] org.hibernate.tool.hbm2ddl.SchemaUpdate : HHH000299: Could not complete schema update
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Access denied for user 'xyz'#'192.168.XX.XX' to database 'xyz'
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:377)
at com.mysql.jdbc.Util.getInstance(Util.java:360)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:978)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3887)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3823)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:870)
at com.mysql.jdbc.MysqlIO.proceedHandshakeWithPluggableAuthentication(MysqlIO.java:1659)
at com.mysql.jdbc.MysqlIO.doHandshake(MysqlIO.java:1206)
at com.mysql.jdbc.ConnectionImpl.coreConnect(ConnectionImpl.java:2234)
at com.mysql.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:2265)
at com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2064)
at com.mysql.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:790)
at com.mysql.jdbc.JDBC4Connection.<init>(JDBC4Connection.java:44)
and Another one in same Exception (though little later)
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 2: alpharaidEntityManagerFactory,dummyTestEntityManagerFactory
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findDefaultEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:572)
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:531)
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$PersistenceElement.resolveEntityManager(PersistenceAnnotationBeanPostProcessor.java:697)
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$PersistenceElement.getResourceToInject(PersistenceAnnotationBeanPostProcessor.java:670)
at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:169)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.postProcessPropertyValues(PersistenceAnnotationBeanPostProcessor.java:354)
... 29 more
My properties files to read connection Details
spring.datasourcedummyTestraid.driver-class-name=com.mysql.jdbc.Driver
spring.datasourcedummyTestraid.url=jdbc:mysql://xx.xx.xx.xx/xyz
spring.datasourcedummyTestraid.username=xxx
spring.datasourcedummyTestraid.password=xxx
spring.datasourcealpharaid.driver-class-name=com.mysql.jdbc.Driver
spring.datasourcealpharaid.url=jdbc:mysql://xx.xx.xx.xx/abc
spring.datasourcealpharaid.username=xxx
spring.datasourcealpharaid.password=xxx
Few Observations:
In exception it can be seen it is trying to connect to my local db ,192.168.XX.XX is my local address.
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Access denied for user 'xyz'#'192.168.XX.XX' to database 'xyz'
(which do not exist) ,I am trying to connect to 2 different remote db's as defined in Properties file.why it goes to local?
when i comment one of the config then other runs fine (though no access problem comes)
problem of
No qualifying bean of type [javax.persistence.EntityManagerFactory] for this i have tried to make one of the Bean primary,tried making it simple function but of no use.
Please help me in solving the problem . Thanks.

You can avoid doing this
#Value("${spring.datasourcealpharaid.driver-class-name}")
String driverClassName = "";
#Value("${spring.datasourcealpharaid.url}")
String url = "";
#Value("${spring.datasourcealpharaid.username}")
String userName = "";
#Value("${spring.datasourcealpharaid.password}")
String password = "";
#Autowired
#Qualifier("jpaMyAlphaVendorAdapter")
JpaVendorAdapter myAlphaVendorAdapter;
#Bean(name = "dummyTestDataSource")
public DataSource dummyTestDataSource() {
return DataSourceBuilder.create().url(url)
.driverClassName(driverClassName).username(userName)
.password(password).build();
}
and instead reduce your code with the lines below:
#ConfigurationProperties(prefix = "spring.datasourcealpharaid")
#Bean
#Primary
public DataSource postgresDataSource() {
return DataSourceBuilder.create().
build();
}
In order to avoid the exception below you can name your bean as a entityManagerFactory
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 2: macraidEntityManagerFactory,nextGenEntityManagerFactory
#Bean(name = "entityManagerFactory")
#Primary
public LocalContainerEntityManagerFactoryBean emf1(EntityManagerFactoryBuilder builder){
return builder
.dataSource(postgresDataSource())
.packages("io.eddumelendez.springdatajpa.domain1")
.persistenceUnit("users")
.build();
}
Checkout the complete configuration here

Related

One Database overrides the other when Primary Bean is defined on and vice versa

I have 2 JDBC Datasources defined in a Spring Boot application utilizing used in a Spring Batch job. However, after autowiring the datasources, only one gets used. The one used is the one annotated #Primary. If I place the annotation on the other JDBC datasource that gets used instead. In a nutshell only one of the JDBC datasources ever gets used. I use Lombok in some places but I'm unsure if that is playing a part.
Here are the datasources:
application.yml
symphony:
datasource:
driver-class-name: oracle.jdbc.OracleDriver
url: ...
type: com.zaxxer.hikari.HikariDataSource
username: <USR>
password: <PWD>
jndi-name: false
repo:
datasource:
driver-class-name: org.h2.Driver
url: jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
username: sa
password: sa
jndi-name: false
Here is the first datasource:
#Configuration
public class RepoDbConfig {
#Bean
#ConfigurationProperties("repo.datasource")
public DataSourceProperties repoDataProperties() {
return new DataSourceProperties();
}
#Bean(name = "repoDataSource")
public DataSource dataSourcerepo() {
DataSource dataSource = repoDataProperties().initializeDataSourceBuilder().type(BasicDataSource.class)
.build();
return dataSource;
}
#Bean(name = "repoJdbcTemplate")
public JdbcTemplate repoJdbcTemplate(DataSource repoDataSource) {
return new JdbcTemplate(repoDataSource);
}
}
Here is the second datasource:
#Configuration
public class SymphonyDbConfig {
#Primary
#Bean
#ConfigurationProperties("symphony.datasource")
public DataSourceProperties symphonyDataSourceProperties() {
return new DataSourceProperties();
}
#Primary
#Bean(name = "symphonyDataSource")
public DataSource dataSourcesymphony() {
HikariDataSource dataSource = symphonyDataSourceProperties().initializeDataSourceBuilder().type(HikariDataSource.class)
.build();
return dataSource;
}
#Primary
#Bean(name = "symphonyJdbcTemplate")
public JdbcTemplate symphonyJdbcTemplate(DataSource symphonyDataSource) {
return new JdbcTemplate(symphonyDataSource);
}
}
The JobRepository beans are configured like this:
#Configuration
#RequiredArgsConstructor
public class JobRepositoryConfig {
final #Qualifier("repoDataSource")
DataSource repoDataSource;
#Bean("repoTransactionManager")
AbstractPlatformTransactionManager repoTransactionManager() {
return new ResourcelessTransactionManager();
}
#Bean("repoJobRepository")
public JobRepository repoJobRepository(DataSource repoDataSource) throws Exception {
JobRepositoryFactoryBean jobRepositoryFactoryBean = new JobRepositoryFactoryBean();
jobRepositoryFactoryBean.setDataSource(repoDataSource);
jobRepositoryFactoryBean.setTransactionManager(repoTransactionManager());
jobRepositoryFactoryBean.setDatabaseType(DatabaseType.H2.getProductName());
return jobRepositoryFactoryBean.getObject();
}
#Bean("repoAppJobLauncher")
public JobLauncher careLocationAppJobLauncher(JobRepository repoJobRepository) {
SimpleJobLauncher simpleJobLauncher = new SimpleJobLauncher();
simpleJobLauncher.setJobRepository(repoJobRepository);
return simpleJobLauncher;
}
}
Finally the Batch Job beans used for the Job are configured here: The only part not shown is the launching of the job. All the required beans used are shown here:
#Configuration
#EnableBatchProcessing
#EnableScheduling
#RequiredArgsConstructor
#Slf4j
public class CellBatchConfig {
private final JobBuilderFactory jobBuilderFactory;
#Qualifier("repoAppJobLauncher")
private final JobLauncher repoAppJobLauncher;
private final StepBuilderFactory stepBuilderFactory;
#Value("${chunk-size}")
private int chunkSize;
#Qualifier("symphonyDataSource")
final DataSource symphonyDataSource;
#Qualifier("repoDataSource")
final DataSource symphonyDataSource;
#Bean
public JdbcPagingItemReader<CenterDto> cellItemReader(PagingQueryProvider pagingQueryProvider) {
return new JdbcPagingItemReaderBuilder<CenterDto>()
.name("cellItemReader")
.dataSource(symphonyDataSource)
.queryProvider(pagingQueryProvider)
.pageSize(chunkSize)
.rowMapper(new CellRowMapper())
.build();
}
#Bean
public PagingQueryProvider pagingQueryProvider() {
OraclePagingQueryProvider pagingQueryProvider = new OraclePagingQueryProvider();
final Map<String, Order> sortKeys = new HashMap<>();
sortKeys.put("ID", Order.ASCENDING);
pagingQueryProvider.setSortKeys(sortKeys);
pagingQueryProvider.setSelectClause(" ID, CELL_NO, MAT_VO ");
pagingQueryProvider.setFromClause(" from pvc.cells");
return pagingQueryProvider;
}
.......
}
The error results from only one of the datasources being used. That results that being used to query the Spring Batch job repository resulting in it failing: Here is the key portion of the stacktrace. It is trying to use the oracle datasource to query for the JobRespository resources and fails as a result:
Caused by: org.springframework.jdbc.BadSqlGrammarException:
PreparedStatementCallback; bad SQL grammar [SELECT JOB_INSTANCE_ID, JOB_NAME from
BATCH_JOB_INSTANCE
where JOB_NAME = ? and JOB_KEY = ?]; nested exception is
java.sql.SQLSyntaxErrorException: ORA-00942: table or view does not exist
In the class JobRepositoryConfig:
In the bean:
#Bean("symphonyJobRepository")
public JobRepository symphonyJobRepository(DataSource repoDataSource) throws Exception {
JobRepositoryFactoryBean jobRepositoryFactoryBean = new JobRepositoryFactoryBean();
jobRepositoryFactoryBean.setDataSource(repoDataSource);
jobRepositoryFactoryBean.setTransactionManager(repoTransactionManager());
jobRepositoryFactoryBean.setDatabaseType(DatabaseType.H2.getProductName());
return jobRepositoryFactoryBean.getObject();
}
You didn't use the variable:
final #Qualifier("repoDataSource") DataSource repoDataSource;
So Spring uses a DataSource object which is annotated with #Primary annotation
I fixed it by making one bean the primary and also adding the qualifiers on the specific beans which had been missing, an omission on my part. For example, here I added the #Qualifier:
#Primary
#Bean(name = "symphonyDataSource")
#Qualifier("symphonyDataSource") // This was missing
public DataSource dataSourcesymphony() {
HikariDataSource dataSource = symphonyDataSourceProperties().initializeDataSourceBuilder().type(HikariDataSource.class)
.build();
return dataSource;
}

Couldn't determine Dialect for "oracle"

I am using Spring boot(2.3.5), Oracle19c DB, and Hibernate(5.4).
I tried to make multi-datasource connection, but I keep getting a dialect error Couldn't determine Dialect for "oracle".
Error creating bean with name 'jdbcDialect' defined in class path resource [org/springframework/boot/autoconfigure/data/jdbc/JdbcRepositoriesAutoConfiguration$SpringBootJdbcConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.relational.core.dialect.Dialect]: Factory method 'jdbcDialect' threw exception; nested exception is org.springframework.data.jdbc.repository.config.DialectResolver$NoDialectException: Cannot determine a dialect for org.springframework.jdbc.core.JdbcTemplate#2ba9ed19. Please provide a Dialect.
I basically followed this tutorial to configure multiple data sources.
application.properties:
spring.datasource-primary.username=oracleprimary
spring.datasource-primary.password=oracleprimary
spring.datasource-primary.url=jdbc:oracle:thin:#//localhost:1521/orcl
spring.datasource-secondary.driver-class-name=oracle.jdbc.OracleDriver
spring.datasource-secondary.username=oraclesecondary
spring.datasource-secondary.password=oraclesecondary
spring.datasource-secondary.url=jdbc:oracle:thin:#//localhost:1521/orcl
Primary configuration:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
entityManagerFactoryRef = "primaryEntityManagerFactory",
transactionManagerRef = "primaryTransactionManager",
basePackages = {"com.foo.primary.repository"})
public class PrimaryDataSourceConfiguration {
#Primary
#Bean(name = "primaryDataSourceProperties")
#ConfigurationProperties("spring.datasource-primary")
public DataSourceProperties primaryDataSourceProperties() {
return new DataSourceProperties();
}
#Primary
#Bean(name = "primaryDataSource")
#ConfigurationProperties("spring.datasource-primary.configuration")
public DataSource primaryDataSource(#Qualifier("primaryDataSourceProperties") DataSourceProperties primaryDataSourceProperties) {
return primaryDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
}
#Primary
#Bean(name = "primaryEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory(
EntityManagerFactoryBuilder primaryEntityManagerFactoryBuilder, #Qualifier("primaryDataSource") DataSource primaryDataSource) {
Map<String, String> primaryJpaProperties = new HashMap<>();
primaryJpaProperties.put("hibernate.dialect", "org.hibernate.dialect.Oracle12cDialect");
return primaryEntityManagerFactoryBuilder
.dataSource(primaryDataSource)
.packages("com.foo.primary.model")
.persistenceUnit("primaryDataSource")
.properties(primaryJpaProperties)
.build();
}
#Primary
#Bean(name = "primaryTransactionManager")
public PlatformTransactionManager primaryTransactionManager(
#Qualifier("primaryEntityManagerFactory") EntityManagerFactory primaryEntityManagerFactory) {
return new JpaTransactionManager(primaryEntityManagerFactory);
}
Second configuration:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
entityManagerFactoryRef = "secondaryEntityManagerFactory",
transactionManagerRef = "secondaryTransactionManager",
basePackages = {"com.foo.secondary.repository"})
public class SecondaryDataSourceConfiguration {
#Bean(name = "secondaryDataSourceProperties")
#ConfigurationProperties("spring.datasource-secondary")
public DataSourceProperties secondaryDataSourceProperties() {
return new DataSourceProperties();
}
#Bean(name = "secondaryDataSource")
#ConfigurationProperties("spring.datasource-secondary.configuration")
public DataSource secondaryDataSource(#Qualifier("secondaryDataSourceProperties") DataSourceProperties secondaryDataSourceProperties) {
return secondaryDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
}
#Bean(name = "secondaryEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean secondaryEntityManagerFactory(
EntityManagerFactoryBuilder secondaryEntityManagerFactoryBuilder, #Qualifier("secondaryDataSource") DataSource secondaryDataSource) {
Map<String, String> secondaryJpaProperties = new HashMap<>();
secondaryJpaProperties.put("hibernate.dialect", "org.hibernate.dialect.Oracle12cDialect");
return secondaryEntityManagerFactoryBuilder
.dataSource(secondaryDataSource)
.packages("com.foo.secondary.model")
.persistenceUnit("secondaryDataSource")
.properties(secondaryJpaProperties)
.build();
}
#Bean(name = "secondaryTransactionManager")
public PlatformTransactionManager secondaryTransactionManager(
#Qualifier("secondaryEntityManagerFactory") EntityManagerFactory secondaryEntityManagerFactory) {
return new JpaTransactionManager(secondaryEntityManagerFactory);
}
}
I also tried org.hibernate.dialect.Oracle10gDialect, and set spring.jpa.database-platform=org.hibernate.dialect.Oracle12cDialect in application.properties, but nothing changed.
How can I properly configure dialect for oracle?
Spring Data JDBC does not support oracle dialect. You need to define your dialect that implements JdbcDialectProvider.
public final class OracleDialect implements DialectResolver.JdbcDialectProvider {
private static Dialect getDialect(Connection connection) throws SQLException {
DatabaseMetaData metaData = connection.getMetaData();
String name = metaData.getDatabaseProductName().toLowerCase(Locale.ROOT);
if (name.contains("oracle")) {
return AnsiDialect.INSTANCE;
}
return null;
}
#Override
public Optional<Dialect> getDialect(JdbcOperations operations) {
return Optional.ofNullable(operations.execute((ConnectionCallback<Dialect>) OracleDialect::getDialect));
}
}
Add spring-boot-starter-data-jdbc dependency in your build.gradle or pom.xml.
Then, as mentioned in the blog, create spring.factories file in resources/META-INF, and paste the following command:
org.springframework.data.jdbc.repository.config.DialectResolver$JdbcDialectProvider=<your-package>.OracleDialect
Also, since both databases you use are the same (OracleDB), you do not need to set .properties() for entity manager. As #SternK mentioned, you can have spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.Oracle12cDialect in your application.properties only.

Spring Boot Data - Getting 'Not a managed Type' error when the package is not included in default entityManager

My application has two entity managers (entityManagerFactory and entityManagerFactorySec). The default is associated with package 'com.abc.model' and the second one is associated with package 'com.abc.uw.model'.
What I observed is that the application startup is fine only if I include the second package as well to the default Entitymanager. Getting the following error even though I see from the logs that the repo got created.
nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dmUwRefRulesRsltRepository': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not a managed type: class com.abc.uw.model.DmUwRefRulesRslt
Java configs are
entityManagerFactory:
return builder.dataSource(dmDs).packages(new String[]{"com.abc.model"}).build();
//startup is fine only with the commented line below
//return builder.dataSource(dmDs).packages(new String[]{"com.abc.model","com.abc.uw.model"}).build();
entityManagerFactorySec:
return builder.dataSource(dataSource).packages(new String[]{
"com.abc.uw.model"}).persistenceUnit("alternate").build();
Could not find why it is not working when the package is included in the packages of the second entitymanager factory
I am providing the complete snippet for both the configs.
Config 1:
#Configuration
#PropertySource("classpath:application.yml")
#EnableJpaRepositories ( basePackages = "com.abc.pcs", entityManagerFactoryRef = "entityManagerFactory")
public class PersistenceConfig {
#Bean(name = "dmDs")
#ConfigurationProperties(prefix = "dm.datasource")
public FactoryBean dmJndiDataSource() {
return new JndiObjectFactoryBean();
}
#Bean("entityBuilder")
public EntityManagerFactoryBuilder entityManagerFactoryBuilder() {
HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
return new EntityManagerFactoryBuilder(hibernateJpaVendorAdapter,
new HashMap<String, Object>(){{put("eclipselink.weaving", "false");}}, null);
}
/**
* #param builder
* #param dmDs
* #return
* #link https://docs.spring.io/spring-boot/docs/current/reference/html/howto-data-access.html#howto-use-two-entity-managers
*/
#Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory( EntityManagerFactoryBuilder builder, #Qualifier("dmDs") final DataSource dmDs) {
LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean = builder.dataSource(dmDs).packages(new String[]{"com.abc.model"}).build();
return localContainerEntityManagerFactoryBean;
}
#Bean("transactionManager")
public PlatformTransactionManager transactionManager(#Qualifier("entityManagerFactory") final EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
}
Config 2:
#Configuration
#PropertySource("classpath:application.yml")
#EnableJpaRepositories ( basePackages = {"com.abc.clp.hnw","com.abc.uw"}, entityManagerFactoryRef = "entityManagerFactorySec")
public class AltPersistenceConfig {
#Bean(name = "dsSecondary")
#ConfigurationProperties(prefix = "ds_secondary.datasource")
public FactoryBean dmEclipseLinkJndiDataSource() {
return new JndiObjectFactoryBean();
}
#Bean(name="entityManagerFactorySec")
public LocalContainerEntityManagerFactoryBean entityManagerFactorySec( EntityManagerFactoryBuilder builder, #Qualifier("dsSecondary") final DataSource dataSource) {
LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean = builder.dataSource(dataSource).packages(new String[]{
"com.abc.uw.model"}).persistenceUnit("alternate").build();
return localContainerEntityManagerFactoryBean;
}
#Bean("transactionManagerSec")
public PlatformTransactionManager transactionManagerEclipseLink(#Qualifier("entityManagerFactorySec") final EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
}
I'm 99% sure that one way or the other you are referencing entities from the second package in the repository for the first one. Either directly or possibly through some attribute of an entity.

Getting NoUniqueBeanDefinitionException when extends QueryDslRepositorySupport and multiple datasources

I need to use multiple databases.
I am using Spring Boot + Spring Data JPA,
so I have two configuration classes:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackages="com.rest.dao.first",
entityManagerFactoryRef = "firstEntityManagerFactory", transactionManagerRef = "firstTransactionManager")
public static class DnbbJdbcConfig {
#Primary
#Bean
#ConfigurationProperties(prefix="datasource.first")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
#Primary
#Bean(name = "firstEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder) {
return builder
.dataSource(dataSource())
.packages("com.rest.dao.first")
.persistenceUnit("first")
.build();
}
#Primary
#Bean(name = "firstTransactionManager")
PlatformTransactionManager transactionManager(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactory(builder).getObject());
}
}
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackages="com.rest.dao.second",
entityManagerFactoryRef = "secondEntityManagerFactory", transactionManagerRef = "secondTransactionManager")
public static class SmsJdbcConfig {
#Bean
#ConfigurationProperties(prefix="datasource.second")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "secondEntityManagerFactory")
#PersistenceContext(unitName = "second")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder) {
return builder
.dataSource(dataSource())
.packages("com.rest.dao.second")
.persistenceUnit("second")
.build();
}
#Bean(name = "secondTransactionManager")
PlatformTransactionManager transactionManager(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactory(builder).getObject());
}
}
I guess there is not error and correct.
So, when I use default repository then not error.
(e.g userRepository.findById() - not error in multi datasources)
But, When I use custom repository then error occur.
(https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.custom-implementations)
Custom Implements
public class FirstRepositoryImpl extends QueryDslRepositorySupport implements FirstCustomRepository {
public FirstRepositoryImpl() {
super(First.class);
}
#PersistenceContext(unitName = "first")
private EntityManager entityManager;
private QFirst first = QFirst.first;
#Override
public List<String> messages() {
JPAQuery query = new JPAQuery(entityManager);
return query.from(first).list(first.message);
}
}
ExceptionTrace
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 2: firstEntityManagerFactory,secondEntityManagerFactory
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findDefaultEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:582) ~[spring-orm-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:541) ~[spring-orm-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$PersistenceElement.resolveEntityManager(PersistenceAnnotationBeanPostProcessor.java:707) ~[spring-orm-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$PersistenceElement.getResourceToInject(PersistenceAnnotationBeanPostProcessor.java:680) ~[spring-orm-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:178) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.postProcessPropertyValues(PersistenceAnnotationBeanPostProcessor.java:354) ~[spring-orm-4.2.3.RELEASE.jar:4.2.3.RELEASE]
... 45 common frames omitted
Did I misconfigure something?
I wrote sample code in my github repository..
https://github.com/okihouse/spring-boot-multiple-datasource-with-querydsl
Solved myself:
I'm check QueryDslRepositorySupport.class and found out.
#PersistenceContext
public void setEntityManager(EntityManager entityManager) {
Assert.notNull(entityManager);
this.querydsl = new Querydsl(entityManager, builder);
this.entityManager = entityManager;
}
#PersistenceContext have not "unitName"
So, Spring can't inject EntityManager.
I create QueryDslRepositorySupportWrapper.java
and inject EntityManager manually.
And It works.
https://github.com/okihouse/spring-boot-multiple-datasource-with-querydsl

BeanDefinitionStoreException exception since trying to switch app to javaconfig from xml config

I am running into some configuration issue since trying to switch to javaconfig from xml config.
Here is the problematic configuration class:
#Configuration
#EnableTransactionManagement(mode = AdviceMode.ASPECTJ)
#Profile({ "default", "cloud" })
public class DataConfiguration {
#Value("${database.driverClassName}")
private String driverClassName;
#Value("${database.url}")
private String url;
#Value("${database.username}")
private String username;
#Value("${database.password}")
private String password;
#Value("${database.validationQuery}")
private String validationQuery;
#Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setTestOnBorrow(Boolean.TRUE);
dataSource.setTestOnReturn(Boolean.TRUE);
dataSource.setTestWhileIdle(Boolean.TRUE);
dataSource.setTimeBetweenEvictionRunsMillis(1800000);
dataSource.setNumTestsPerEvictionRun(3);
dataSource.setMinEvictableIdleTimeMillis(1800000);
dataSource.setValidationQuery(validationQuery);
dataSource.setMaxActive(5);
dataSource.setLogAbandoned(Boolean.TRUE);
dataSource.setRemoveAbandoned(Boolean.TRUE);
dataSource.setRemoveAbandonedTimeout(10);
return dataSource;
}
#Bean
public JpaTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory());
return transactionManager;
}
#Bean
public HibernateJpaVendorAdapter jpaVendorAdapter() {
return new HibernateJpaVendorAdapter();
}
#Bean
public HibernatePersistence persistenceProvider() {
return new HibernatePersistence();
}
#Bean(name = "entityManagerFactory", destroyMethod = "close")
public EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setPackagesToScan("com.bignibou.domain");
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setPersistenceProvider(persistenceProvider());
entityManagerFactoryBean.setJpaVendorAdapter(jpaVendorAdapter());
entityManagerFactoryBean.setJpaPropertyMap(propertiesMap());
return entityManagerFactoryBean.getObject();
}
public Map<String, String> propertiesMap() {
Map<String, String> propertiesMap = new HashMap<>();
propertiesMap.put("hibernate.dialect", "org.hibernate.dialect.MySQL5InnoDBDialect");
propertiesMap.put("hibernate.hbm2ddl.auto", "update");
propertiesMap.put("hibernate.ejb.naming_strategy", "org.hibernate.cfg.ImprovedNamingStrategy");
propertiesMap.put("hibernate.connection.charSet", "UTF-8");
propertiesMap.put("hibernate.show_sql", "true");
propertiesMap.put("hibernate.format_sql", "true");
propertiesMap.put("hibernate.use_sql_comments", "true");
return propertiesMap;
}
#Bean
public HibernateExceptionTranslator hibernateExceptionTranslator() {
return new HibernateExceptionTranslator();
}
}
Here is the exception I get:
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public static javax.persistence.EntityManager org.springframework.orm.jpa.SharedEntityManagerCreator.createSharedEntityManager(javax.persistence.EntityManagerFactory)] threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:181)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:570)
... 121 more
Caused by: java.lang.NullPointerException
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.initProxyClassLoader(SharedEntityManagerCreator.java:151)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.<init>(SharedEntityManagerCreator.java:143)
at org.springframework.orm.jpa.SharedEntityManagerCreator.createSharedEntityManager(SharedEntityManagerCreator.java:118)
at org.springframework.orm.jpa.SharedEntityManagerCreator.createSharedEntityManager(SharedEntityManagerCreator.java:96)
at org.springframework.orm.jpa.SharedEntityManagerCreator.createSharedEntityManager(SharedEntityManagerCreator.java:64)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:160)
... 122 more
It seems there's an issue with the entityManagerFactory config... What I am getting wrong?
If you are not using the entityManagerFactory() method anywhere in your java configuration, you can instead return the LocalContainerEntityManagerFactoryBean object.
The LocalContainerEntityManagerFactoryBean is both an InitializingBean and a FactoryBean. These are special interfaces that Spring can use to initialize a bean and then add it to the context.
You could therefore change your method to
#Bean(name = "entityManagerFactory", destroyMethod = "close")
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setPackagesToScan("com.bignibou.domain");
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setPersistenceProvider(persistenceProvider());
entityManagerFactoryBean.setJpaVendorAdapter(jpaVendorAdapter());
entityManagerFactoryBean.setJpaPropertyMap(propertiesMap());
return entityManagerFactoryBean;
}
Spring will take care of calling afterPropertiesSet() and getObject() on the object returned by the method and adding the created EntityManagerFactory bean to the context.
This is detailed in the IoC chapter of the Spring documentation.
adding the following line sorted the issue:
entityManagerFactoryBean.setJpaPropertyMap(propertiesMap());
entityManagerFactoryBean.afterPropertiesSet();//NOTICE HERE!!!
return entityManagerFactoryBean.getObject();

Resources