引言
在软件开发中,多数据源的应用越来越普遍,特别是在微服务架构和业务模块化的场景下。多数据源能够让不同的业务模块和微服务拥有各自独立的数据存储,大大提高了系统的灵活性和可维护性。本文将深入探讨多数据源的配置和实施,以及在Spring Boot环境下,如何通过Spring Data JPA和Gradle来实现多数据源的管理和应用。
本文讨论的多数据源指的是关系型数据库,即一个服务有多个这样的数据库。1.1 多数据源的必要性
随着业务的发展和演变,单一数据源已经无法满足多元化和复杂化的业务需求。多数据源的应用不仅能够更好地支持业务的发展,还能够有效地实现资源隔离和管理,减少系统的耦合度,提高服务的稳定性和可用性。使用多数据源可以有如下几个优点:
- 性能优化:不同的关系型数据库有各自的优势和特性,一些数据库更适合读取操作,而另一些数据库更适合写入操作。通过将读写负载分配到不同的数据库实例上,可以优化性能。
- 数据隔离:在一个系统中,有些数据可能更重要,需要更高的安全性和可靠性;而其他数据可能不太重要,可以容忍一定程度的数据丢失。这个时候,将不同类型的数据存储在不同的数据库中,可以实现数据的隔离,满足不同的数据安全和可靠性需求。
- 业务逻辑隔离:在复杂的系统中,不同的模块或子系统可能有不同的业务逻辑和数据处理需求。为不同的模块或子系统使用不同的数据库,可以简化系统的设计和维护。
1.2 多数据源的应用场景
常见到的几个大型项目的业务场景如下:
- 金融系统:金融系统通常要处理大量的事务数据和报表数据。将事务处理和报表生成分配到不同的数据库可以优化性能和简化系统设计。
- 电商平台:电商平台通常会涉及到用户信息、订单数据、商品数据等多种类型的数据。为这些不同类型的数据使用不同的数据库实例可以实现数据和业务逻辑的隔离。
- ERP系统:企业资源规划(ERP)系统通常包含多个模块,例如财务、人力资源和供应链管理。为每个模块使用独立的数据库可以使得开发和维护更加便捷。
以下所有示例均已上传至Github上,大家可以将项目拉取到本地进行运行
Github示例(如果对Gradle还不熟练,建议翻看我之前的文章):gradle-spring-boot-demo
实战演示
本章将详细说明如何在Spring Boot项目中实施多数据源。我们会一步一步地演示如何配置两个H2数据库实例作为我们的数据源。
2.1 创建实体类
首先,我们创建两个实体类,一个用于主数据源,一个用于次数据源。我们在这里以User
实体为例。请确保您的实体类在正确的包中。
// 主数据源实体
@Entity
@Data
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
}
// 次数据源实体
@Entity
@Table(name = "orders")
@Data
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String orderNumber;
private Double amount;
}
2.2 配置数据源
接下来,我们需要在application.yml
中配置两个数据源:
spring:
datasource:
primary:
jdbc-url: jdbc:h2:file:./multi-datasource/data/testdb1
driver-class-name: org.h2.Driver
username: sa
password: password
secondary:
jdbc-url: jdbc:h2:file:./multi-datasource/data/testdb2
driver-class-name: org.h2.Driver
username: sa
password: password
h2:
console:
enabled: true
jpa:
hibernate:
ddl-auto: update
show-sql: true
这里,我们配置了两个H2数据库实例,一个作为主数据源,一个作为次数据源。
2.3 实现数据源配置类
为了实现多数据源,我们需要创建两个配置类,PrimaryDataSourceConfig
和SecondaryDataSourceConfig
,并在其中定义DataSource
、EntityManagerFactory
和TransactionManager
的beans。
@Configuration
@EnableJpaRepositories(
basePackages = "org.kfaino.datasource.repository.primary")
@EntityScan(basePackages = {"org.kfaino.datasource.entity.primary"})
public class PrimaryDataSourceConfig {
@Primary
@Bean(name = "primaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
@Primary
@Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory(
EntityManagerFactoryBuilder builder,
@Qualifier("primaryDataSource") DataSource dataSource) {
return builder
.dataSource(dataSource)
.packages("org.kfaino.datasource.entity.primary") // 设置实体类的包路径
.persistenceUnit("primary")
.properties(hibernateProperties())
.build();
}
private Map<String, Object> hibernateProperties() {
Map<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto", "update");
properties.put("hibernate.show_sql", true);
return properties;
}
@Primary
@Bean(name = "transactionManager")
public PlatformTransactionManager transactionManager(
@Qualifier("entityManagerFactory") EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
}
@Configuration
@EnableJpaRepositories(
basePackages = "org.kfaino.datasource.repository.secondary",
entityManagerFactoryRef = "secondaryEntityManagerFactory",
transactionManagerRef = "secondaryTransactionManager")
@EntityScan(basePackages = {"org.kfaino.datasource.entity.primary"})
public class SecondaryDataSourceConfig {
@Bean(name = "secondaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.secondary")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "secondaryEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean secondaryEntityManagerFactory(
EntityManagerFactoryBuilder builder,
@Qualifier("secondaryDataSource") DataSource dataSource) {
return builder
.dataSource(dataSource)
.packages("org.kfaino.datasource.entity.secondary") // 设置实体类的包路径
.persistenceUnit("secondary")
.properties(hibernateProperties())
.build();
}
private Map<String, Object> hibernateProperties() {
Map<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto", "update");
properties.put("hibernate.show_sql", true);
return properties;
}
@Bean(name = "secondaryTransactionManager")
public PlatformTransactionManager secondaryTransactionManager(
@Qualifier("secondaryEntityManagerFactory") EntityManagerFactory secondaryEntityManagerFactory) {
return new JpaTransactionManager(secondaryEntityManagerFactory);
}
}