在企業(yè)級應(yīng)用開發(fā)中,一個項目往往需要連接多個數(shù)據(jù)庫。Spring Boot 作為一款廣泛使用的 Java 開發(fā)框架,提供了便捷的方式來實現(xiàn)連接多個數(shù)據(jù)庫的功能。本文將詳細(xì)介紹在 Spring Boot 中實現(xiàn)連接多個數(shù)據(jù)庫的技巧,幫助開發(fā)者更好地應(yīng)對復(fù)雜的數(shù)據(jù)庫使用場景。
1. 項目環(huán)境搭建
首先,我們需要創(chuàng)建一個 Spring Boot 項目??梢允褂?Spring Initializr 來快速生成項目骨架,選擇合適的依賴,如 Spring Web、Spring Data JPA、相應(yīng)的數(shù)據(jù)庫驅(qū)動(如 MySQL、PostgreSQL 等)。以下是一個使用 Maven 構(gòu)建的示例 pom.xml 文件:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>multi-db-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>multi-db-demo</name>
<description>Demo project for Spring Boot multi database connection</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>2. 配置多個數(shù)據(jù)源
在 application.properties 或 application.yml 文件中配置多個數(shù)據(jù)源的連接信息。以下是 application.yml 的示例:
spring:
datasource:
primary:
url: jdbc:mysql://localhost:3306/primary_db
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
secondary:
url: jdbc:mysql://localhost:3306/secondary_db
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver這里我們配置了兩個數(shù)據(jù)源,分別命名為 primary 和 secondary。
3. 創(chuàng)建數(shù)據(jù)源配置類
接下來,我們需要創(chuàng)建數(shù)據(jù)源配置類,分別配置主數(shù)據(jù)源和從數(shù)據(jù)源。以下是示例代碼:
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource;
@Configuration
public class DataSourceConfig {
@Primary
@Bean(name = "primaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
@Bean(name = "secondaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.secondary")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
}在這個配置類中,我們使用 @Primary 注解標(biāo)記主數(shù)據(jù)源,使用 @ConfigurationProperties 注解從配置文件中讀取數(shù)據(jù)源信息。
4. 配置 JPA 實體管理器和事務(wù)管理器
為了使用 JPA 操作數(shù)據(jù)庫,我們需要為每個數(shù)據(jù)源配置實體管理器和事務(wù)管理器。以下是示例代碼:
import org.springframework.beans.factory.annotation.Qualifier;
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.persistence.EntityManagerFactory;
import javax.sql.DataSource;
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "primaryEntityManagerFactory",
transactionManagerRef = "primaryTransactionManager",
basePackages = {"com.example.multi.db.demo.repository.primary"}
)
public class PrimaryJpaConfig {
@Primary
@Bean(name = "primaryEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory(
EntityManagerFactoryBuilder builder,
@Qualifier("primaryDataSource") DataSource dataSource
) {
return builder
.dataSource(dataSource)
.packages("com.example.multi.db.demo.entity.primary")
.persistenceUnit("primary")
.build();
}
@Primary
@Bean(name = "primaryTransactionManager")
public PlatformTransactionManager primaryTransactionManager(
@Qualifier("primaryEntityManagerFactory") EntityManagerFactory entityManagerFactory
) {
return new JpaTransactionManager(entityManagerFactory);
}
}
@Configuration
@EnableJpaRepositories(
entityManagerFactoryRef = "secondaryEntityManagerFactory",
transactionManagerRef = "secondaryTransactionManager",
basePackages = {"com.example.multi.db.demo.repository.secondary"}
)
public class SecondaryJpaConfig {
@Bean(name = "secondaryEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean secondaryEntityManagerFactory(
EntityManagerFactoryBuilder builder,
@Qualifier("secondaryDataSource") DataSource dataSource
) {
return builder
.dataSource(dataSource)
.packages("com.example.multi.db.demo.entity.secondary")
.persistenceUnit("secondary")
.build();
}
@Bean(name = "secondaryTransactionManager")
public PlatformTransactionManager secondaryTransactionManager(
@Qualifier("secondaryEntityManagerFactory") EntityManagerFactory entityManagerFactory
) {
return new JpaTransactionManager(entityManagerFactory);
}
}這里我們分別為兩個數(shù)據(jù)源配置了實體管理器和事務(wù)管理器,并指定了實體類和倉庫接口的包路徑。
5. 創(chuàng)建實體類和倉庫接口
根據(jù)不同的數(shù)據(jù)源,我們需要創(chuàng)建對應(yīng)的實體類和倉庫接口。以下是示例代碼:
// 主數(shù)據(jù)源實體類
package com.example.multi.db.demo.entity.primary;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class PrimaryEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// getters and setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
// 主數(shù)據(jù)源倉庫接口
package com.example.multi.db.demo.repository.primary;
import com.example.multi.db.demo.entity.primary.PrimaryEntity;
import org.springframework.data.jpa.repository.JpaRepository;
public interface PrimaryRepository extends JpaRepository<PrimaryEntity, Long> {
}
// 從數(shù)據(jù)源實體類
package com.example.multi.db.demo.entity.secondary;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class SecondaryEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String description;
// getters and setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
// 從數(shù)據(jù)源倉庫接口
package com.example.multi.db.demo.repository.secondary;
import com.example.multi.db.demo.entity.secondary.SecondaryEntity;
import org.springframework.data.jpa.repository.JpaRepository;
public interface SecondaryRepository extends JpaRepository<SecondaryEntity, Long> {
}這里我們分別為兩個數(shù)據(jù)源創(chuàng)建了實體類和倉庫接口,注意實體類和倉庫接口的包路徑要與前面配置的一致。
6. 創(chuàng)建服務(wù)層和控制器層
最后,我們創(chuàng)建服務(wù)層和控制器層來測試數(shù)據(jù)庫連接。以下是示例代碼:
// 服務(wù)層
package com.example.multi.db.demo.service;
import com.example.multi.db.demo.entity.primary.PrimaryEntity;
import com.example.multi.db.demo.entity.secondary.SecondaryEntity;
import com.example.multi.db.demo.repository.primary.PrimaryRepository;
import com.example.multi.db.demo.repository.secondary.SecondaryRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class MultiDbService {
@Autowired
private PrimaryRepository primaryRepository;
@Autowired
private SecondaryRepository secondaryRepository;
public List<PrimaryEntity> getAllPrimaryEntities() {
return primaryRepository.findAll();
}
public List<SecondaryEntity> getAllSecondaryEntities() {
return secondaryRepository.findAll();
}
}
// 控制器層
package com.example.multi.db.demo.controller;
import com.example.multi.db.demo.entity.primary.PrimaryEntity;
import com.example.multi.db.demo.entity.secondary.SecondaryEntity;
import com.example.multi.db.demo.service.MultiDbService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class MultiDbController {
@Autowired
private MultiDbService multiDbService;
@GetMapping("/primary")
public List<PrimaryEntity> getPrimaryEntities() {
return multiDbService.getAllPrimaryEntities();
}
@GetMapping("/secondary")
public List<SecondaryEntity> getSecondaryEntities() {
return multiDbService.getAllSecondaryEntities();
}
}在服務(wù)層中,我們注入了兩個數(shù)據(jù)源的倉庫接口,實現(xiàn)了獲取數(shù)據(jù)的方法。在控制器層中,我們創(chuàng)建了兩個接口,分別用于獲取主數(shù)據(jù)源和從數(shù)據(jù)源的數(shù)據(jù)。
7. 總結(jié)
通過以上步驟,我們成功實現(xiàn)了 Spring Boot 連接多個數(shù)據(jù)庫的功能。在實際開發(fā)中,我們可以根據(jù)需要配置更多的數(shù)據(jù)源,并且可以使用不同的數(shù)據(jù)庫類型。同時,我們還可以通過事務(wù)管理器來管理跨數(shù)據(jù)源的事務(wù)。希望本文介紹的技巧能幫助開發(fā)者更好地應(yīng)對復(fù)雜的數(shù)據(jù)庫使用場景。
需要注意的是,在處理多個數(shù)據(jù)源時,要確保實體類和倉庫接口的包路徑正確,避免出現(xiàn)混淆。此外,對于性能要求較高的場景,可以考慮使用連接池來提高數(shù)據(jù)庫連接的效率。
總之,Spring Boot 提供了強大的功能來支持連接多個數(shù)據(jù)庫,開發(fā)者可以根據(jù)具體需求靈活配置和使用。