在企业级应用开发中,一个项目往往需要连接多个数据库。Spring Boot 作为一款广泛使用的 Java 开发框架,提供了便捷的方式来实现连接多个数据库的功能。本文将详细介绍在 Spring Boot 中实现连接多个数据库的技巧,帮助开发者更好地应对复杂的数据库使用场景。
1. 项目环境搭建
首先,我们需要创建一个 Spring Boot 项目。可以使用 Spring Initializr 来快速生成项目骨架,选择合适的依赖,如 Spring Web、Spring Data JPA、相应的数据库驱动(如 MySQL、PostgreSQL 等)。以下是一个使用 Maven 构建的示例 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. 配置多个数据源
在 application.properties 或 application.yml 文件中配置多个数据源的连接信息。以下是 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这里我们配置了两个数据源,分别命名为 primary 和 secondary。
3. 创建数据源配置类
接下来,我们需要创建数据源配置类,分别配置主数据源和从数据源。以下是示例代码:
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 注解标记主数据源,使用 @ConfigurationProperties 注解从配置文件中读取数据源信息。
4. 配置 JPA 实体管理器和事务管理器
为了使用 JPA 操作数据库,我们需要为每个数据源配置实体管理器和事务管理器。以下是示例代码:
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);
}
}这里我们分别为两个数据源配置了实体管理器和事务管理器,并指定了实体类和仓库接口的包路径。
5. 创建实体类和仓库接口
根据不同的数据源,我们需要创建对应的实体类和仓库接口。以下是示例代码:
// 主数据源实体类
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;
}
}
// 主数据源仓库接口
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> {
}
// 从数据源实体类
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;
}
}
// 从数据源仓库接口
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> {
}这里我们分别为两个数据源创建了实体类和仓库接口,注意实体类和仓库接口的包路径要与前面配置的一致。
6. 创建服务层和控制器层
最后,我们创建服务层和控制器层来测试数据库连接。以下是示例代码:
// 服务层
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();
}
}在服务层中,我们注入了两个数据源的仓库接口,实现了获取数据的方法。在控制器层中,我们创建了两个接口,分别用于获取主数据源和从数据源的数据。
7. 总结
通过以上步骤,我们成功实现了 Spring Boot 连接多个数据库的功能。在实际开发中,我们可以根据需要配置更多的数据源,并且可以使用不同的数据库类型。同时,我们还可以通过事务管理器来管理跨数据源的事务。希望本文介绍的技巧能帮助开发者更好地应对复杂的数据库使用场景。
需要注意的是,在处理多个数据源时,要确保实体类和仓库接口的包路径正确,避免出现混淆。此外,对于性能要求较高的场景,可以考虑使用连接池来提高数据库连接的效率。
总之,Spring Boot 提供了强大的功能来支持连接多个数据库,开发者可以根据具体需求灵活配置和使用。