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.