Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Connecting to multiple database in spring boot

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);
        }
    }

}
like image 671
Virat Avatar asked Aug 06 '18 15:08

Virat


2 Answers

In your TaskServiceImpl make sure you annotate the persistenceContext correctly.

For example:

@PersistenceContext(unitName = "entityManagerFactory")
private EntityManager em;
like image 188
Dan Avatar answered Sep 18 '22 16:09

Dan


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.

like image 34
Naanavanalla Avatar answered Sep 18 '22 16:09

Naanavanalla