I need to connect to two database in my project. So I created two configuration files.
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories( basePackages = {"com.virat.webservices.datastore.v1.Repo" } )
@EntityScan("com.virat.webservices.datastore.v1.Model")
public class V1DBConfig {
@Primary
@Bean( name = "dataSource" )
@ConfigurationProperties( prefix = "v1.datasource" )
public DataSource dataSource()
{
return DataSourceBuilder.create().build();
}
@Primary
@Bean( name = "entityManagerFactory" )
public LocalContainerEntityManagerFactoryBean entityManagerFactory( EntityManagerFactoryBuilder builder,
@Qualifier( "dataSource" ) DataSource dataSource )
{
return builder.dataSource(dataSource).packages("com.virat.webservices.datastore.v1.Model")
.persistenceUnit("db1").build();
}
@Primary
@Bean( name = "transactionManager" )
public PlatformTransactionManager transactionManager(
@Qualifier( "entityManagerFactory" ) EntityManagerFactory entityManagerFactory )
{
return new JpaTransactionManager(entityManagerFactory);
}
}
and
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories( entityManagerFactoryRef = "v2EntityManagerFactory", transactionManagerRef = "v2TransactionManager", basePackages = {
"com.virat.datastore.repository" } )
@EntityScan( "com.virat.datastore.model" )
public class V2DBConfig {
@Bean( name = "v2DataSource" )
@ConfigurationProperties( prefix = "spring.datasource" )
public DataSource dataSource()
{
return DataSourceBuilder.create().build();
}
@Bean( name = "v2EntityManagerFactory" )
public LocalContainerEntityManagerFactoryBean barEntityManagerFactory( EntityManagerFactoryBuilder builder,
@Qualifier( "v2DataSource" ) DataSource dataSource )
{
return builder.dataSource(dataSource).packages("com.virat.model")
.persistenceUnit("db2").build();
}
@Bean( name = "v2TransactionManager" )
public PlatformTransactionManager barTransactionManager(
@Qualifier( "v2EntityManagerFactory" ) EntityManagerFactory barEntityManagerFactory )
{
return new JpaTransactionManager(barEntityManagerFactory);
}
}
And I configured my application.properties
file as,
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/db2? useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=fal. se&serverTimezone=UTC&useSSL=false
spring.datasource.username=root
spring.datasource.password=
#spring.datasource.pool.size=20
v1.datasource.driver-class-name=com.mysql.jdbc.Driver
v1.datasource.url=jdbc:mysql://localhost:3306/db1? useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=fal. se&serverTimezone=UTC&useSSL=false
v1.datasource.username=root
v1.datasource.password=
#v1.datasource.pool.size=20
spring.jpa.properties.hibernate.id.new_generator_mappings=false
v1.jpa.properties.hibernate.id.new_generator_mappings=false
#spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
But when I run the application, the following exception has been thrown.
***************************
APPLICATION FAILED TO START
***************************
Description:
Field entityManager in com.highpeak.tlp.webservices.services.impl.TaskServiceImpl required a single bean, but 2 were found:
- org.springframework.orm.jpa.SharedEntityManagerCreator#0: defined by method 'createSharedEntityManager' in null
- org.springframework.orm.jpa.SharedEntityManagerCreator#1: defined by method 'createSharedEntityManager' in null
Action:
Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed
org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter:42 -
***************************
APPLICATION FAILED TO START
***************************
Description:
Field entityManager in com.highpeak.tlp.webservices.services.impl.TaskServiceImpl required a single bean, but 2 were found:
- org.springframework.orm.jpa.SharedEntityManagerCreator#0: defined by method 'createSharedEntityManager' in null
- org.springframework.orm.jpa.SharedEntityManagerCreator#1: defined by method 'createSharedEntityManager' in null
Action:
Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed
Disconnected from the target VM, address: '127.0.0.1:56875', transport: 'socket'
Process finished with exit code 1
I am unable to identify what is the error. I have two modules. The repository
and entity
class of one database is in one module and the other database's classes in another module. Is this causing issue?
EDIT
My TaskServiceImpl.java
package com.virat.webservices.services.impl;
@Service
public class TaskServiceImpl implements TaskService {
private static final Logger LOGGER = LoggerFactory.getLogger(TaskServiceImpl.class);
@Autowired
@PersistenceContext(unitName = "v2EntityManagerFactory")
private EntityManager entityManager;
@Value( "${file.base.path}" )
private String basePath;
@Value( "${application.domain}" )
private String applicationDomain;
@Value( "${application.protocol}" )
private String applicationProtocol;
@Value( "${server.port}" )
private String serverPort;
@Override
@SuppressWarnings( "unchecked" )
@Transactional( rollbackOn = DataException.class )
public Integer doSomething( SomeObject someObject,
UserAccessDetails userAccessDetails ) throws DataException
{
try
{
// Do input validations
if( NullEmptyUtils.isNull(userAccessDetails) || NullEmptyUtils.isNull(someObject) )
{
throw new DataException(GeneralConstants.EXCEPTION, GeneralConstants.NULL_INPUT_ERROR,
HttpStatus.BAD_REQUEST);
}
// Creates a native mysql query based on the contents of lawyerDiscoveryParamsBean
/* Should be replaced with criteria API */
String generatedQuery = DynamicQueryGenerator.getDynamicQuery(someObject, owner);
LOGGER.info("Generated query: {}", generatedQuery);
Query executableQuery = entityManager.createNativeQuery(generatedQuery, UserModel.class);
List<UserModel> userModels = executableQuery.getResultList();
if( userModels.isEmpty() )
{
return 0;
}
return 1;
}
catch( DataException e )
{
LOGGER.error(GeneralConstants.ERROR, e);
throw e;
}
catch( Exception e )
{
LOGGER.error(GeneralConstants.ERROR, e);
throw new DataException(GeneralConstants.EXCEPTION, GeneralConstants.SOMETHING_WENT_WRONG,
HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
In your TaskServiceImpl
make sure you annotate the persistenceContext correctly.
For example:
@PersistenceContext(unitName = "entityManagerFactory")
private EntityManager em;
In V1DBConfig.java
, the annotation @EnableJpaRepository
should actually be like this,
@EnableJpaRepositories( entityManagerFactoryRef = "entityManagerFactory", transactionManagerRef = "transactionManager", basePackages = {
"com.virat.webservices.datastore.v1.Repo" } )
You have done the configuration right in the class V2DBConfig.java
(Look at the @EnableJpaRepository
annotation). Do the same thing in V1DBConfig.java
.
And then, in your TaskServiceImpl.java
, provide PersistenceContext
, as answered by @Dan. I hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With