¿Cómo puedo configurar y usar dos fuentes de datos?
Por ejemplo, esto es lo que tengo para la primera fuente de datos:
aplicación.propiedades
#first db
spring.datasource.url = [url]
spring.datasource.username = [username]
spring.datasource.password = [password]
spring.datasource.driverClassName = oracle.jdbc.OracleDriver
#second db ...
Clase de aplicación
@SpringBootApplication
public class SampleApplication
{
public static void main(String[] args) {
SpringApplication.run(SampleApplication.class, args);
}
}
como modifico application.properties agregar otra fuente de datos? ¿Cómo lo conecto automáticamente para que lo use un repositorio diferente?
A veces, es posible que deba asignar la fuente de datos, el administrador de transacciones y SqlSessionFactory como principal.
– Dai Kaixian
15 de diciembre de 2016 a las 10:37
@K. Siva Prasad Reddy Está bien, pero tengo 2 repositorios JPAR diferentes. ¿Cómo sabe Spring Boot qué fuente de datos usar? Cada JPARepository debería usar una base de datos diferente
Tenga en cuenta que tengo @Bean(name="datasource1") y @Bean(name="datasource2")entonces puede usarlo cuando necesitemos una fuente de datos como @Qualifier("datasource1") y @Qualifier("datasource2") por ejemplo
@Transactional //this will use the first datasource because it is @primary
o
@Transactional("tm2")
La parte más importante, de la que difícilmente encontrarás un ejemplo en ningún sitio: si desea un método para confirmar/deshacer transacciones de ambas bases de datos, necesita ChainedTransactionManager para tm1 y tm2, así:
@Bean(name = "chainedTransactionManager")
public ChainedTransactionManager getChainedTransactionManager(@Qualifier ("tm1") DataSourceTransactionManager tm1, @Qualifier ("tm2") DataSourceTransactionManager tm2){
return new ChainedTransactionManager(tm1, tm2);
}
Para usarlo, agregue esta anotación en un método @Transactional(value=”chainedTransactionManager”) por ejemplo
@Transactional(value="chainedTransactionManager")
public void insertAll() {
UserBean test = new UserBean();
test.setUsername("username" + new Date().getTime());
userDao.insert(test);
userDao2.insert(test);
}
Esto debería ser suficiente. Ver ejemplo y detalle en el enlace de arriba.
Hola, @Surasin Tancharoen, estamos tratando de mantener dos fuentes de datos con los mismos datos para que, si una falla, la aplicación se ejecute en la otra fuente de datos. ¿Estará bien el enfoque anterior?
– Arun Sudhakaran
13 de mayo de 2020 a las 5:02
@ArunSudhakaran No. Esta solución no funcionará como respaldo. Si busca alta disponibilidad, la mayoría de las bases de datos ya tienen configuraciones para ejecutar varias bases de datos con una única IP virtual. prueba eso en su lugar.
Crear más de una fuente de datos funciona igual que crear la primera. Es posible que desee marcar uno de ellos como @Primary si está utilizando la configuración automática predeterminada para JDBC o JPA (entonces ese será seleccionado por cualquier inyección de @Autowired).
@Bean
@Primary
@ConfigurationProperties(prefix="datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix="datasource.secondary")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
Gracias por el enlace a la documentación oficial sobre esto.
– Manoj Shrestha
10 sep 2021 a las 19:29
También tuve que configurar la conexión a 2 fuentes de datos desde la aplicación Spring Boot, y no fue fácil: la solución mencionada en el Documentación de Spring Boot no funcionó Después de una larga búsqueda en Internet, lo hice funcionar y la idea principal fue tomada de Este artículo y un montón de otros lugares.
La siguiente solución está escrita en kotlin y trabaja con Arranque de primavera 2.1.3 y Núcleo de hibernación 5.3.7. El problema principal era que no bastaba con configurar diferentes Fuente de datos configs, pero también era necesario configurar EntityManagerFactory y TransactionManager para ambas bases de datos.
Aquí está la configuración para la primera base de datos (Principal):
@Configuration
@EnableJpaRepositories(
entityManagerFactoryRef = "firstDbEntityManagerFactory",
transactionManagerRef = "firstDbTransactionManager",
basePackages = ["org.path.to.firstDb.domain"]
)
@EnableTransactionManagement
class FirstDbConfig {
@Bean
@Primary
@ConfigurationProperties(prefix = "spring.datasource.firstDb")
fun firstDbDataSource(): DataSource {
return DataSourceBuilder.create().build()
}
@Primary
@Bean(name = ["firstDbEntityManagerFactory"])
fun firstDbEntityManagerFactory(
builder: EntityManagerFactoryBuilder,
@Qualifier("firstDbDataSource") dataSource: DataSource
): LocalContainerEntityManagerFactoryBean {
return builder
.dataSource(dataSource)
.packages(SomeEntity::class.java)
.persistenceUnit("firstDb")
// Following is the optional configuration for naming strategy
.properties(
singletonMap(
"hibernate.naming.physical-strategy",
"org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl"
)
)
.build()
}
@Primary
@Bean(name = ["firstDbTransactionManager"])
fun firstDbTransactionManager(
@Qualifier("firstDbEntityManagerFactory") firstDbEntityManagerFactory: EntityManagerFactory
): PlatformTransactionManager {
return JpaTransactionManager(firstDbEntityManagerFactory)
}
}
Y esta es la configuración para la segunda base de datos:
El problema con las propiedades era que tenía que definir jdbc-url en vez de URL porque de lo contrario tenía una excepción.
PD
También es posible que tenga diferentes esquemas de nombres en sus bases de datos, como fue mi caso. Dado que Hibernate 5 no es compatible con todos los esquemas de nombres anteriores, tuve que usar la solución de esta respuesta; tal vez también ayude a alguien.
este código no se ejecutará de la forma en que 2 anotaciones @primary funcionan juntas en la misma base de datos.
– Rohit Chaurasiya
24 de julio de 2020 a las 2:51
de hecho, pero este código menciona una parte importante con la configuración manual de propiedades en lugar de simple y llanamente return DataSourceBuilder.create().build(); que aparentemente no funciona, por lo tanto, mi voto a favor va aquí
– soy_infame
20 oct 2020 a las 15:38
Raju Ranjan
# Here '1stDB' is the database name
spring.datasource.url=jdbc:mysql://localhost/A
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
# Here '2ndDB' is the database name
spring.second-datasourcee.url=jdbc:mysql://localhost/B
spring.second-datasource.username=root
spring.second-datasource.password=root
spring.second-datasource.driver-class-name=com.mysql.jdbc.Driver
@Bean
@Primary
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource firstDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "spring.second-datasource")
public DataSource secondDataSource() {
return DataSourceBuilder.create().build();
}
este código no se ejecutará de la forma en que 2 anotaciones @primary funcionan juntas en la misma base de datos.
– Rohit Chaurasiya
24 de julio de 2020 a las 2:51
de hecho, pero este código menciona una parte importante con la configuración manual de propiedades en lugar de simple y llanamente return DataSourceBuilder.create().build(); que aparentemente no funciona, por lo tanto, mi voto a favor va aquí
– soy_infame
20 oct 2020 a las 15:38
Anil Konduru
Mi requisito era ligeramente diferente pero usaba dos fuentes de datos.
He usado dos fuentes de datos para las mismas entidades JPA del mismo paquete. Uno para ejecutar DDL en el inicio del servidor para crear/actualizar tablas y otro para DML en tiempo de ejecución.
La conexión DDL debe cerrarse después de que se ejecuten las declaraciones DDL, para evitar el uso posterior de previllages de superusuario en cualquier parte del código.
// Primera clase de configuración para la fuente de datos DDL
public class DatabaseDDLConfig {
@Bean
public LocalContainerEntityManagerFactoryBean ddlEntityManagerFactoryBean() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
PersistenceProvider persistenceProvider = new
org.hibernate.jpa.HibernatePersistenceProvider();
entityManagerFactoryBean.setDataSource(ddlDataSource());
entityManagerFactoryBean.setPackagesToScan(new String[] {
"com.test.two.data.sources"});
HibernateJpaVendorAdapter vendorAdapter = new
HibernateJpaVendorAdapter();
entityManagerFactoryBean.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.dialect",
"org.hibernate.dialect.PostgreSQLDialect");
properties.put("hibernate.physical_naming_strategy",
"org.springframework.boot.orm.jpa.hibernate.
SpringPhysicalNamingStrategy");
properties.put("hibernate.implicit_naming_strategy",
"org.springframework.boot.orm.jpa.hibernate.
SpringImplicitNamingStrategy");
properties.put("hibernate.hbm2ddl.auto", "update");
entityManagerFactoryBean.setJpaPropertyMap(properties);
entityManagerFactoryBean.setPersistenceUnitName("ddl.config");
entityManagerFactoryBean.setPersistenceProvider(persistenceProvider);
return entityManagerFactoryBean;
}
@Bean
public DataSource ddlDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("spring.datasource.driver-class-name"));
dataSource.setUrl(env.getProperty("spring.datasource.url"));
dataSource.setUsername(env.getProperty("ddl.user");
dataSource.setPassword(env.getProperty("ddl.password"));
return dataSource;
}
@Bean
public PlatformTransactionManager ddlTransactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(ddlEntityManagerFactoryBean().getObject());
return transactionManager;
}
}
//2da clase de configuración para la fuente de datos DML
public class DatabaseDMLConfig {
@Bean
@Primary
public LocalContainerEntityManagerFactoryBean dmlEntityManagerFactoryBean() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
PersistenceProvider persistenceProvider = new org.hibernate.jpa.HibernatePersistenceProvider();
entityManagerFactoryBean.setDataSource(dmlDataSource());
entityManagerFactoryBean.setPackagesToScan(new String[] { "com.test.two.data.sources" });
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
entityManagerFactoryBean.setJpaVendorAdapter(vendorAdapter);
entityManagerFactoryBean.setJpaProperties(defineJpaProperties());
entityManagerFactoryBean.setPersistenceUnitName("dml.config");
entityManagerFactoryBean.setPersistenceProvider(persistenceProvider);
return entityManagerFactoryBean;
}
@Bean
@Primary
public DataSource dmlDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("spring.datasource.driver-class-name"));
dataSource.setUrl(envt.getProperty("spring.datasource.url"));
dataSource.setUsername("dml.user");
dataSource.setPassword("dml.password");
return dataSource;
}
@Bean
@Primary
public PlatformTransactionManager dmlTransactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(dmlEntityManagerFactoryBean().getObject());
return transactionManager;
}
}
//Uso de fuentes de datos DDL en el código.
public class DDLServiceAtStartup {
//Import persistence unit ddl.config for ddl purpose.
@PersistenceUnit(unitName = "ddl.config")
private EntityManagerFactory entityManagerFactory;
public void executeDDLQueries() throws ContentServiceSystemError {
try {
EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
entityManager.createNativeQuery("query to create/update table").executeUpdate();
entityManager.flush();
entityManager.getTransaction().commit();
entityManager.close();
//Close the ddl data source to avoid from further use in code.
entityManagerFactory.close();
} catch(Exception ex) {}
}
//Uso de la fuente de datos DML en el código.
public class DDLServiceAtStartup {
@PersistenceUnit(unitName = "dml.config")
private EntityManagerFactory entityManagerFactory;
public void createRecord(User user) {
userDao.save(user);
}
}
¿Ha sido útil esta solución?
Tu feedback nos ayuda a saber si la solución es correcta y está funcionando. De esta manera podemos revisar y corregir el contenido.
Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos.
Configurar y más información