Saltar al contenido

Spring Data JPA: múltiples repositorios EnableJpa

Ya no tienes que indagar más por otras webs ya que llegaste al lugar indicado, contamos con la solución que buscas y sin complicaciones.

Solución:

Para dejar que la primavera sepa qué DataSource está relacionado con lo que Repository deberías definirlo en el @EnableJpaRepositories anotación. Supongamos que tenemos dos entidades, la Servers entidad y la Domains entidad y cada uno tiene su propio Repositorio, luego cada Repositorio tiene su propia configuración JpaDataSource.

1. Agrupe todos los repositorios según la fuente de datos con la que están relacionados. Por ejemplo

Repositorio de Domains entidades (paquete: org.springdemo.multiple.datasources.repository.domains):

package org.springdemo.multiple.datasources.repository.domains;

import org.springdemo.multiple.datasources.domain.domains.Domains;
import org.springframework.data.jpa.repository.JpaRepository;

public interface DomainsRepository extends JpaRepository 

Repositorio de Servers entidades (paquete: org.springdemo.multiple.datasources.repository.servers)

package org.springdemo.multiple.datasources.repository.servers;

import org.springdemo.multiple.datasources.domain.servers.Servers;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ServersRepository extends JpaRepository 

2. Para cada JPA Data Soruce necesitas definir una configuración, en este ejemplo muestro cómo configurar dos DataSources diferentes

Domains Configuración Jpa: la relación entre la fuente de datos y el repositorio se define en el basePackages value, por eso es necesario agrupar los repositorios en diferentes paquetes en función del gestor de entidades que utilizará cada repositorio.

@Configuration
@EnableJpaRepositories(
        entityManagerFactoryRef = "domainsEntityManager",
        transactionManagerRef = "domainsTransactionManager",
        basePackages = "org.springdemo.multiple.datasources.repository.domains"
        )
public class DomainsConfig {

Servers Configuración de la fuente de datos: como puede ver, el valor de basePackages tiene el nombre de paquete del Servers Repositorio, y también los valores de entityManagerFactoryRef y transactionManagerRef son diferentes para permitir que Spring separe cada entityManager.

@Configuration
@EnableJpaRepositories(
        entityManagerFactoryRef = "serversEntityManager",
        transactionManagerRef = "serversTransactionManager",
        basePackages = "org.springdemo.multiple.datasources.repository.servers"
        )
public class ServersConfig {

3. Establecer una fuente de datos como principal

Para evitar el mensaje de error: Parameter 0 of constructor in org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration required a single bean, but 2 were found: simplemente establezca una de las fuentes de datos como @Primary, en este ejemplo selecciono el Servers Fuente de datos como principal:

@Bean("serversDataSourceProperties")
@Primary
@ConfigurationProperties("app.datasource.servers")
public DataSourceProperties serversDataSourceProperties()
    return new DataSourceProperties();




@Bean("serversDataSource")
@Primary
@ConfigurationProperties("app.datasource.servers")
public DataSource serversDataSource(@Qualifier("serversDataSourceProperties") DataSourceProperties serversDataSourceProperties) 
    return serversDataSourceProperties().initializeDataSourceBuilder().build();

Si necesita más información, consulte el ejemplo completo de cada configuración:

Servers Configuración JPA

@Configuration
@EnableJpaRepositories(
        entityManagerFactoryRef = "serversEntityManager",
        transactionManagerRef = "serversTransactionManager",
        basePackages = "org.springdemo.multiple.datasources.repository.servers"
        )
public class ServersConfig 

    @Bean(name = "serversEntityManager")
    public LocalContainerEntityManagerFactoryBean getServersEntityManager(EntityManagerFactoryBuilder builder,
                                                                          @Qualifier("serversDataSource") DataSource serversDataSource)


        return builder
                .dataSource(serversDataSource)
                .packages("org.springdemo.multiple.datasources.domain.servers")
                .persistenceUnit("servers")
                .properties(additionalJpaProperties())
                .build();

    

    Map additionalJpaProperties()
        Map map = new HashMap<>();

        map.put("hibernate.hbm2ddl.auto", "create");
        map.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
        map.put("hibernate.show_sql", "true");

        return map;
    


    @Bean("serversDataSourceProperties")
    @Primary
    @ConfigurationProperties("app.datasource.servers")
    public DataSourceProperties serversDataSourceProperties()
        return new DataSourceProperties();
    



    @Bean("serversDataSource")
    @Primary
    @ConfigurationProperties("app.datasource.servers")
    public DataSource serversDataSource(@Qualifier("serversDataSourceProperties") DataSourceProperties serversDataSourceProperties) 
        return serversDataSourceProperties().initializeDataSourceBuilder().build();
    

    @Bean(name = "serversTransactionManager")
    public JpaTransactionManager transactionManager(@Qualifier("serversEntityManager") EntityManagerFactory serversEntityManager)
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(serversEntityManager);

        return transactionManager;
    

Domains Configuración JPA

@Configuration
@EnableJpaRepositories(
        entityManagerFactoryRef = "domainsEntityManager",
        transactionManagerRef = "domainsTransactionManager",
        basePackages = "org.springdemo.multiple.datasources.repository.domains"
        )
public class DomainsConfig 

    @Bean(name = "domainsEntityManager")
    public LocalContainerEntityManagerFactoryBean getdomainsEntityManager(EntityManagerFactoryBuilder builder
    ,@Qualifier("domainsDataSource") DataSource domainsDataSource)

        return builder
                .dataSource(domainsDataSource)
                .packages("org.springdemo.multiple.datasources.domain.domains")
                .persistenceUnit("domains")
                .properties(additionalJpaProperties())
                .build();

    


    Map additionalJpaProperties()
        Map map = new HashMap<>();

        map.put("hibernate.hbm2ddl.auto", "create");
        map.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
        map.put("hibernate.show_sql", "true");

        return map;
    


    @Bean("domainsDataSourceProperties")
    @ConfigurationProperties("app.datasource.domains")
    public DataSourceProperties domainsDataSourceProperties()
        return new DataSourceProperties();
    


    @Bean("domainsDataSource")
    public DataSource domainsDataSource(@Qualifier("domainsDataSourceProperties") DataSourceProperties domainsDataSourceProperties) 
        return domainsDataSourceProperties.initializeDataSourceBuilder().build();
    

    @Bean(name = "domainsTransactionManager")
    public JpaTransactionManager transactionManager(@Qualifier("domainsEntityManager") EntityManagerFactory domainsEntityManager)
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(domainsEntityManager);

        return transactionManager;
    


Para separar cada fuente de datos, puse la configuración en el application.properties archivo, así:

app.datasource.domains.url=jdbc:h2:mem:~/test
app.datasource.domains.driver-class-name=org.h2.Driver


app.datasource.servers.driver-class-name=com.mysql.jdbc.Driver
app.datasource.servers.url=jdbc:mysql://localhost:3306/v?autoReconnect=true&useSSL=false
app.datasource.servers.username=myuser
app.datasource.servers.password=mypass

Si necesita más información, consulte la siguiente documentación:

Spring Documentation: howto-two-datasources

Un ejemplo similar de cómo configurar dos bases de datos diferentes: ejemplo de github

La respuesta proporcionada por @Daniel C. es correcta. Pequeña corrección / observación de mi lado.

  • @Primario no es obligatorio si no desea marcar ninguna fuente de datos como predeterminada; de lo contrario, es necesario.
  • Si está definiendo alguno de los EntityManagerFactoryBean con @Frijol nombrar como entityManagerFactory entonces es mejor marcarlo @Primario para evitar conflictos.
  • @ConfigurationProperties (“app.datasource.servers”) se puede marcar a nivel de clase en lugar de definir a nivel de método.
  • Mejor volver HikariDataSource como fuente de datos si usa Spring Boot 2.xo una versión superior, ya que se ha cambiado.
  • Asegúrese de definir la propiedad exacta para jdbc-url que está siendo utilizado por
    HikariDataSource para hacer referencia a la URL de conexión JDBC.

Aquí tienes las comentarios y puntuaciones

Si tienes alguna cuestión o disposición de afinar nuestro tutorial te insinuamos ejecutar una apostilla y con gusto lo observaremos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *