Eric Borges
Eric Borges

Reputation: 1

Read-replica SpringBoot Hibernate

I want to distibute my consults in my BD-01 in my another BD-02, those are the same with the same data (Microsoft SQL Server Enterprise), however the consults on my application only directs to my BD-01

I did some tests in my private project but it is not working: PrimaryDBConfig


package com.example.wsappsiav.MultipleDatabase;

import jakarta.persistence.EntityManagerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
basePackages = {"com.example.wsappsiav.Repository"},
entityManagerFactoryRef = "entityManagerFactory1",
transactionManagerRef = "transactionManager1"
)
public class PrimaryDbConfig {

    @Bean
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }
    
    @Primary
    @Bean(name = "entityManagerFactory1")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory1(
            EntityManagerFactoryBuilder builder, @Qualifier("primaryDataSource") DataSource dataSource) {
        System.out.println("OPA < 01");
        return builder
                .dataSource(dataSource)
                .packages("com.example.wsappsiav.Entity")
                .build();
    }
    
    @Primary
    @Bean(name = "transactionManager1")
    public PlatformTransactionManager transactionManager1(
            @Qualifier("entityManagerFactory1") EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
    }

}

SecondaryDBConfig

package com.example.wsappsiav.MultipleDatabase;

import jakarta.persistence.EntityManagerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
basePackages = {"com.example.wsappsiav.Repository"},
entityManagerFactoryRef = "entityManagerFactory2",
transactionManagerRef = "transactionManager2"
)
public class SecondaryDbConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }
    
    @Bean(name = "entityManagerFactory2")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory2(
            EntityManagerFactoryBuilder builder, @Qualifier("secondaryDataSource") DataSource dataSource) {
        Map<String, Object> properties = new HashMap<>();
        properties.put("hibernate.readOnly", true);
    
        return builder
                .dataSource(dataSource)
                .packages("com.example.wsappsiav.Entity")
                .build();
    }
    
    @Bean(name = "transactionManager2")
    public PlatformTransactionManager transactionManager2(
            @Qualifier("entityManagerFactory2") EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
    }

}

application.properties

spring.datasource.primary.jdbc-url=hide
spring.datasource.primary.username=hide
spring.datasource.primary.password=hide
spring.datasource.primary.driver-class-name=hide

spring.datasource.secondary.jdbc-url=hide
spring.datasource.secondary.username=hide
spring.datasource.secondary.password=hied
spring.datasource.secondary.driver-class-name=hide

Error:

***************************

APPLICATION FAILED TO START

***************************

Description:

The bean 'veiculoRepository', defined in com.example.wsappsiav.Repository.VeiculoRepository defined in @EnableJpaRepositories declared on SecondaryDbConfig, could not be registered. A bean with that name has already been defined in com.example.wsappsiav.Repository.VeiculoRepository defined in @EnableJpaRepositories declared on PrimaryDbConfig and overriding is disabled.

Action:

Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true

Can anyone help me?

With these configurations i was expecting the possibility off change my consults to the DB i want like this:

package com.example.wsappsiav.Service;

import com.example.wsappsiav.Entity.Cliente;
import com.example.wsappsiav.Repository.ClienteRepository;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

@Service
@Transactional(transactionManager = "transactionManager1")
public class ClienteService {

    @Autowired
    @Qualifier("entityManagerFactory2")
    private EntityManagerFactory entityManagerFactory2;
    
    @Autowired
    @Qualifier("transactionManager2")
    private PlatformTransactionManager transactionManager2;
    
    @Autowired
    @Qualifier("entityManagerFactory1")
    private EntityManagerFactory entityManagerFactory1;
    
    @Autowired
    @Qualifier("transactionManager1")
    private PlatformTransactionManager transactionManager1;
    
    @Autowired
    private ClienteRepository clienteRepository;
    
    public List<Cliente> listarTodosClientes() {
        EntityManager entityManager = entityManagerFactory2.createEntityManager();
        return clienteRepository.findAll();
    }
    
    public Optional<Cliente> buscarClientePorId(Long id) {
        EntityManager entityManager = entityManagerFactory2.createEntityManager();
        return clienteRepository.findById(id);
    }
    
    public Cliente salvarCliente(Cliente cliente) {
        return clienteRepository.save(cliente);
    }
    
    public void deletarCliente(Long id) {
        clienteRepository.deleteById(id);
    }
    
    public Cliente buscarClientePorCpfCnpj(String cpfCnpj){
        EntityManager entityManager = entityManagerFactory1.createEntityManager();
        return clienteRepository.findClienteByCpfCnpj(cpfCnpj);
    };

}

When i use the configuration : setting spring.main.allow-bean-definition-overriding=true

it olny consults in the BD-02

Upvotes: 0

Views: 23

Answers (0)

Related Questions