跳过正文

配置多个数据源在 Spring Boot 中

Spring Database
作者
Harpal Singh
Software Engineer
翻译者
Namastecode
目录

1. 介绍

在这个简短的教程中,我们将学习如何在Spring Boot应用程序中配置多个数据源。

想象一下,我们正在开发一个电子商务应用程序,并且需要两个独立的数据库来存储客户和订单。我们将把它们配置为独立的数据源,并看看如何在我们的应用程序中使用它们。

2. 配置属性

让我们先在 application.properties 中为我们的 Customer 和 Order 数据源定义一些属性:

#Customer db
spring.datasource.customer.url = [url]
spring.datasource.customer.username = [username]
spring.datasource.customer.password = [password] 
spring.datasource.customer.driverClassName = org.postgresql.Driver

#Order db
spring.datasource.order.url = [url]
spring.datasource.order.username = [username]
spring.datasource.order.password = [password]
spring.datasource.order.driverClassName = org.sqlite.JDBC

在上面,我们定义了两个数据库的数据源及其各自的属性。此外,我们还可以配置不同类型的数据库。

现在,我们可以在应用程序中使用这些属性。

3. 配置数据源

接下来,我们将创建一个配置类,在其中为每个数据库定义两个 DataSource bean:

@Configuration
public class CustomerOrderDataSourcesConfiguration {

  @Primary 
  @Bean(name = "customerDataSource")
  @ConfigurationProperties(prefix = "spring.datasource.customer") 
  public DataSource customerDataSource() {
      return DataSourceBuilder.create().build();
  }

  @Bean(name = "orderDataSource")
  @ConfigurationProperties(prefix = "spring.datasource.order")
  public DataSource orderDataSource() {
      return DataSourceBuilder.create().build();  
  }

}

我们明确命名我们的bean,以便可以通过@Qualifier注解决定引用哪个数据源。此外,我们将customerDataSource标记为@Primary,并将其视为我们应用程序的主要数据库。因此,如果我们不使用@Qualifier注解,Spring将在需要的地方注入客户数据源。

让我们看看如何使用这些beans。

4. 使用数据源

我们可以在应用程序中根据需要注入这两个数据源。 例如,我们可以使用 @Autowired 注解在服务类中注入数据源:

@Autowired  
@Qualifier("orderDataSource")
private DataSource orderDataSource;

然而,大多数时候,我们希望将数据源连接到Spring Data JPA仓库,并使用它来代替直接与数据源交互。

接下来让我们看看如何配置。

5. 配置 @Repository 使用特定的数据源

首先,我们需要创建一个配置类,在其中使用 @EnableJpaRepositories 注解来扫描仓库,并为每个数据源定义实体管理器工厂:

@Configuration
@EnableJpaRepositories(
  basePackages = "com.namastecode.repositories.customer",
  entityManagerFactoryRef = "customerEntityManagerFactory", 
  transactionManagerRef = "customerTransactionManager"
)
public class CustomerDataSourceConfiguration{
  // More code
}

现在,我们需要在这个类中创建 entityManagerFactory bean:

@Primary
@Bean(name = "customerEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean customerEntityManagerFactory(
  EntityManagerFactoryBuilder builder,
  @Qualifier("customerDataSource") DataSource dataSource) {
  return builder
    .dataSource(dataSource)
    .packages("com.namastecode.domain.customer") // entities package
    .persistenceUnit("customers")
    .build();
}

接下来,我们将创建 transactionManager bean,以便每个数据源都有自己的事务管理器,并且不会相互冲突:

@Primary
@Bean(name = "customerTransactionManager")
public PlatformTransactionManager customerTransactionManager(
  @Qualifier("customerEntityManagerFactory") EntityManagerFactory customerEntityManagerFactory) {
  return new JpaTransactionManager(customerEntityManagerFactory);
}

在上面,我们将两个 bean 都定义为 @Primary,因为客户数据源是默认的。对于订单数据源,我们不需要这样做。

我们已准备好在包 com.namastecode.domain.customer 下创建我们的实体:

@Entity
@Table(name = "customers")
public class Customer {
  // More code
}

同样,我们可以在包 com.namastecode.repositories.customer 下创建这些仓库:

@Repository
public interface CustomerRepository extends JpaRepository<Customer, Long> {
  // More code
}

现在,我们有两个独立的数据源及其资源。然而,可能会出现一种情况,我们希望配置数据源,以便在两个数据源之间使用单个事务。接下来,让我们看看如何做到这一点。

6. 配置一个链式事务管理器

如果我们想在两个数据源之间执行事务,我们可以设置一个 ChainedTransactionManager bean,之后在我们的操作中可以使用:

@Bean(name = "chainedTransactionManager")
public ChainedTransactionManager chainedTransactionManager(
  @Qualifier("customerTransactionManager") PlatformTransactionManager customerTransactionManager,
  @Qualifier("orderTransactionManager") PlatformTransactionManager orderTransactionManager) {
  return new ChainedTransactionManager(customerTransactionManager, orderTransactionManager);
}

接下来,假设我们有一个 CustomerOrderService,在这里我们使用了 CustomerRepositoryOrderRepository。因此,为了在这个服务类中使用我们的链式事务管理器,我们可以显式地定义事务管理器:

@Service
public class CustomerOrderService {

  @Autowired
  private CustomerRepository customerRepository;
  
  @Autowired
  private OrderRepository orderRepository;

  @Transactional(transactionManager = "chainedTransactionManager") 
  public void updateCustomerAndOrder(Customer customer, Order order) {
    customerRepository.save(customer);
    orderRepository.save(order);
  }

}

上面,如果任何保存操作失败,事务将为这两个数据源回滚。

7. 结论

在本教程中,我们学习了如何在Spring Boot应用程序中配置多个数据源。

首先,我们定义了每个数据源的属性,创建了数据源 beans,使用特定的数据源配置了 @Repository,最后,我们了解了如何为两个数据源配置共享的事务管理器。

相关文章

配置 Java Web 客户端以进行 HTTPS 请求
WebClient HTTPS Spring
在 Docker 容器中运行 PostgreSQL
DevOps Postgres Docker Database
在 Spring 中获取 Properties 文件中定义的值
Spring Properties Basics