Spring Boot konfiguriert und verwendet zwei Datenquellen
Lesezeit: 11 Minuten
Juventus
Wie kann ich zwei Datenquellen konfigurieren und verwenden?
Hier ist zum Beispiel, was ich für die erste Datenquelle habe:
application.properties
#first db
spring.datasource.url = [url]
spring.datasource.username = [username]
spring.datasource.password = [password]
spring.datasource.driverClassName = oracle.jdbc.OracleDriver
#second db ...
Anwendungsklasse
@SpringBootApplication
public class SampleApplication
{
public static void main(String[] args) {
SpringApplication.run(SampleApplication.class, args);
}
}
Wie ändere ich application.properties eine weitere Datenquelle hinzufügen? Wie kann ich es automatisch verdrahten, damit es von einem anderen Repository verwendet wird?
K. Shiva Prasad Reddy
Bitte schön.
Fügen Sie Ihre Datei application.properties hinzu:
Manchmal müssen Sie möglicherweise datasource, transactionManager und SqlSessionFactory als primär all zuweisen.
– Dai Kaixian
15. Dezember 2016 um 10:37 Uhr
@K. Siva Prasad Reddy OK, aber ich habe 2 verschiedene JPARrepositories – woher weiß Spring Boot, welche DataSource verwendet werden soll? Jedes JPARepository sollte eine andere Datenbank verwenden
Beachten Sie, dass ich habe @Bean(name="datasource1") und @Bean(name="datasource2")dann können Sie es verwenden, wenn wir eine Datenquelle als benötigen @Qualifier("datasource1") und @Qualifier("datasource2") zum Beispiel
@Transactional //this will use the first datasource because it is @primary
oder
@Transactional("tm2")
Der wichtigste Teil, von dem Sie kaum ein Beispiel finden werden: Wenn Sie eine Methode zum Commit/Rollback von Transaktionen beider Datenbanken wünschen, benötigen Sie ChainedTransactionManager für tm1 und tm2 wie folgt:
@Bean(name = "chainedTransactionManager")
public ChainedTransactionManager getChainedTransactionManager(@Qualifier ("tm1") DataSourceTransactionManager tm1, @Qualifier ("tm2") DataSourceTransactionManager tm2){
return new ChainedTransactionManager(tm1, tm2);
}
Um sie zu verwenden, fügen Sie diese Annotation beispielsweise in einer Methode @Transactional(value=”chainedTransactionManager”) hinzu
@Transactional(value="chainedTransactionManager")
public void insertAll() {
UserBean test = new UserBean();
test.setUsername("username" + new Date().getTime());
userDao.insert(test);
userDao2.insert(test);
}
Das sollte reichen. Siehe Beispiel und Details im obigen Link.
Hallo @Surasin Tancharoen, wir versuchen, zwei Datenquellen mit denselben Daten zu behalten, damit die Anwendung bei einem Ausfall auf der anderen Datenquelle ausgeführt wird. Wird der obige Ansatz in Ordnung sein?
– Arun Sudhakaran
13. Mai 2020 um 5:02 Uhr
@ArunSudhakaran Nein. Diese Lösung funktioniert nicht als Backup. Wenn Sie nach hoher Verfügbarkeit suchen, verfügen die meisten Datenbanken bereits über Konfigurationen zum Ausführen mehrerer Datenbanken mit einer einzigen virtuellen IP. versuchen Sie es stattdessen.
Das Erstellen von mehr als einer Datenquelle funktioniert genauso wie das Erstellen der ersten. Möglicherweise möchten Sie eine davon als @Primary markieren, wenn Sie die standardmäßige automatische Konfiguration für JDBC oder JPA verwenden (dann wird diese von allen @Autowired-Injektionen übernommen).
@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();
}
Vielen Dank für den Link zur offiziellen Dokumentation dazu.
– Manoj Shrestha
10. September 2021 um 19:29 Uhr
Ich musste auch eine Verbindung zu 2 Datenquellen aus der Spring Boot-Anwendung herstellen, und es war nicht einfach – die in der erwähnte Lösung Spring Boot-Dokumentation hat nicht funktioniert. Nach langem Suchen im Internet habe ich es zum Laufen gebracht und die Hauptidee war übernommen Dieser Artikel und viele andere Orte.
Die folgende Lösung ist eingeschrieben Kotlin und arbeitet mit Springboot 2.1.3 und Hibernate Core 5.3.7. Das Hauptproblem war, dass es nicht ausreichte, einfach nur anders einzurichten Datenquelle configs, aber es war auch notwendig zu konfigurieren EntityManagerFactory und Transaktionsmanager für beide Datenbanken.
Hier ist die Konfiguration für die erste (primäre) Datenbank:
@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)
}
}
Und das ist die Konfiguration für die zweite Datenbank:
Problem mit Eigenschaften war, dass ich definieren musste jdbc-url Anstatt von URL denn sonst hatte ich eine ausnahme.
p.s
Außerdem haben Sie möglicherweise unterschiedliche Namensschemata in Ihren Datenbanken, was bei mir der Fall war. Da Hibernate 5 nicht alle vorherigen Benennungsschemata unterstützt, musste ich die Lösung aus dieser Antwort verwenden – vielleicht hilft es auch jemandem.
Dieser Code wird nicht ausgeführt, wenn 2 @primary-Anmerkungen in derselben Datenbank zusammenarbeiten.
– Rohit Chaurasiya
24. Juli 2020 um 2:51 Uhr
in der Tat, aber dieser Code erwähnt einen wichtigen Teil mit manueller Einstellung der Eigenschaften anstelle von schlicht und einfach return DataSourceBuilder.create().build(); was anscheinend nicht funktioniert, daher geht meine positive Bewertung hierher
– im_berüchtigt
20. Oktober 2020 um 15:38 Uhr
Raj 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();
}
Dieser Code wird nicht ausgeführt, wenn 2 @primary-Anmerkungen in derselben Datenbank zusammenarbeiten.
– Rohit Chaurasiya
24. Juli 2020 um 2:51 Uhr
in der Tat, aber dieser Code erwähnt einen wichtigen Teil mit manueller Einstellung der Eigenschaften anstelle von schlicht und einfach return DataSourceBuilder.create().build(); was anscheinend nicht funktioniert, daher geht meine positive Bewertung hierher
– im_berüchtigt
20. Oktober 2020 um 15:38 Uhr
Anil Konduru
Meine Anforderung war etwas anders, verwendete aber zwei Datenquellen.
Ich habe zwei Datenquellen für dieselben JPA-Entitäten aus demselben Paket verwendet. Einer zum Ausführen von DDL beim Serverstart zum Erstellen/Aktualisieren von Tabellen und ein weiterer für DML zur Laufzeit.
Die DDL-Verbindung sollte geschlossen werden, nachdem DDL-Anweisungen ausgeführt wurden, um die weitere Verwendung von Superuser-Vorrechten an beliebiger Stelle im Code zu verhindern.
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;
}
}
//2. Konfigurationsklasse für DML-Datenquelle
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;
}
}
//Verwendung von DDL-Datenquellen im Code.
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) {}
}
//Verwendung der DML-Datenquelle im Code.
public class DDLServiceAtStartup {
@PersistenceUnit(unitName = "dml.config")
private EntityManagerFactory entityManagerFactory;
public void createRecord(User user) {
userDao.save(user);
}
}
10191400cookie-checkSpring Boot konfiguriert und verwendet zwei Datenquellenyes