知識庫 / Spring / Spring Boot RSS 訂閱

Flyway 在 Spring Boot 中使用多個數據庫

Persistence,Spring Boot
HongKong
4
10:43 AM · Dec 06 ,2025

1. 概述

當使用微服務或複雜單體應用時,通常會使用多個數據庫來處理不同的領域,例如用户、產品等。Spring Boot 提供了強大的支持來管理此類多數據庫配置。但是,管理多個數據庫的模式遷移可能會比較複雜。

在本教程中,我們將探索如何將 Flyway 集成到 Spring Boot 中,以支持單個應用程序中的多個數據庫。我們將使用兩個獨立的 H2 內存數據庫——一個用於用户,一個用於產品,並分別使用 Flyway 對每個數據庫應用遷移。

2. Maven 配置

在開始之前,我們將通過 Spring Initializr,使用 Maven 創建一個簡單的 Spring Boot 應用程序。

首先,我們需要配置所需的依賴項。 我們包括 Spring Boot Starter 依賴項,用於 數據 JPAFlywayH2測試。 這些依賴項將允許我們使用 Flyway 來管理模式版本和使用 JPA 與數據庫層進行交互:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
    <version>3.2.3</version>
</dependency>
<dependency>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-core</artifactId>
    <version>9.22.3</version>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>2.2.224</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <version>3.2.3</version>
    <scope>test</scope>
</dependency>

這些依賴項對於啓用模式遷移、設置內存數據庫以及編寫驗證單元測試至關重要。

3. 多個數據庫配置

本節將定義數據源、Flyway Bean、JPA 配置以及所有必要的組件,以支持多個數據庫連接和模式遷移。Spring Boot 支持單數據源的自動配置,因此對於多個數據庫,我們需要手動提供自定義配置。 這包括為每個數據庫創建單獨的數據源 Bean、實體管理器工廠和事務管理器。

我們還需要單獨配置 Flyway,以便每個數據庫可以運行其遷移腳本。 這些配置確保了職責的清晰分離,並防止衝突。

3.1. 應用屬性

我們的 <em >application.yml</em> 配置精簡,因為我們通過在 <em >UserDbConfig</em><em >ProductDbConfig</em> 類中程序化配置數據源來實現配置。我們只保留一個屬性,用於允許 Spring 中的循環引用,從而避免在更復雜的配置中可能出現的 Bean 依賴問題:

spring:
  main:
    allow-circular-references: true

我們故意從 application.yml 中省略了數據源配置,以避免混淆,因為所有連接詳細信息都已硬編碼在各自的配置類中。 這種方法使此示例專注於演示 Flyway 多數據庫支持,而不是外部屬性綁定。

3.2. 用户實體

User 實體是一個簡單的 JPA 模型,用於在 userdb 數據庫中表示與用户相關的元數據。它包含兩個關鍵字段:idname,這兩個字段都存儲在列中:

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
}

3.3 產品實體

產品實體用於模型產品相關數據,這些數據存儲在productdb數據庫中。它包含兩個主要字段:idtitle。 類似於User實體,它使用標準JPA註解來定義持久化行為:

@Entity
@Table(name = "products")
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "product_seq")
    private Long id;

    private String name;
}

這兩個實體支持所有 CRUD 操作,並與配置好的相應數據源無縫集成,以執行 ORM 映射。

3.4. 倉庫 (Repositories)

倉庫接口負責封裝訪問數據源所需的邏輯。對於每個實體,如 UserProduct,我們定義一個獨立的倉庫接口,該接口擴展了 JpaRepository 接口。 這種擴展使 Spring Data JPA 能夠自動生成標準數據訪問方法,例如 findByIdsavedeleteByIdfindAll,而無需編寫冗餘代碼。

public interface UserRepository extends JpaRepository<User, Long> {}
public interface ProductRepository extends JpaRepository<Product, Long> {}

UserRepositoryuserdb 交互,而 ProductRepository 則連接到 productdb,基於各自的配置。這些接口在保持代碼整潔、可讀性和與實際持久化邏輯的解耦方面發揮着關鍵作用。

3.5. 配置類

在多數據庫環境中,Spring Boot 不會自動管理多個數據源或遷移腳本。因此,我們需要顯式配置每個數據庫的連接、實體掃描、事務管理和 Flyway 遷移設置。

我們為每個數據庫,如 userdbproductdb,定義了單獨的配置類,以保持設置的模塊化和可維護性。這種顯式配置確保每個數據庫都能運行其遷移並管理其事務邊界,從而避免衝突或運行時歧義。

以下是 userdb 的配置:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
  basePackages = "com.baeldung.repository.user",
  entityManagerFactoryRef = "userEntityManagerFactory",
  transactionManagerRef = "userTransactionManager"
)
public class UserDbConfig {
    @Bean
    @Primary
    public DataSource userDataSource() {
        return DataSourceBuilder.create()
          .url("jdbc:h2:mem:userdb")
          .username("sa")
          .password("")
          .driverClassName("org.h2.Driver")
          .build();
    }

    @Bean
    @Primary
    public LocalContainerEntityManagerFactoryBean userEntityManagerFactory(
      EntityManagerFactoryBuilder builder) {
        return builder
          .dataSource(userDataSource())
          .packages("com.baeldung.entity")
          .persistenceUnit("userPU")
          .properties(Map.of("hibernate.hbm2ddl.auto", "none"))
          .build();
    }

    @Bean
    @Primary
    public PlatformTransactionManager userTransactionManager(
      EntityManagerFactory userEntityManagerFactory) {
        return new JpaTransactionManager(userEntityManagerFactory);
    }

    @PostConstruct
    public void migrateUserDb() {
        Flyway.configure()
          .dataSource(userDataSource())
          .locations("classpath:db/migration/userdb")
          .load()
          .migrate();
    }
}

配置必須精確,針對productdb,但需要不同的包和遷移路徑:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
  basePackages = "com.baeldung.repository.product",
  entityManagerFactoryRef = "productEntityManagerFactory",
  transactionManagerRef = "productTransactionManager"
)
public class ProductDbConfig {
    @Bean
    public DataSource productDataSource() {
        return DataSourceBuilder.create()
          .url("jdbc:h2:mem:productdb")
          .username("sa")
          .password("")
          .driverClassName("org.h2.Driver")
          .build();
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean productEntityManagerFactory(
      EntityManagerFactoryBuilder builder) {
        return builder
          .dataSource(productDataSource())
          .packages("com.baeldung.entity")
          .persistenceUnit("productPU")
          .properties(Map.of("hibernate.hbm2ddl.auto", "none"))
          .build();
    }

    @Bean
    public PlatformTransactionManager productTransactionManager(
      EntityManagerFactory productEntityManagerFactory) {
        return new JpaTransactionManager(productEntityManagerFactory);
    }

    @PostConstruct
    public void migrateProductDb() {
        Flyway.configure()
          .dataSource(productDataSource())
          .locations("classpath:db/migration/productdb")
          .load()
          .migrate();
    }
}

3.6. SQL 遷移

Flyway 使用版本化的 SQL 腳本來管理數據庫模式變更,以一種可預測和可重複的方式進行。 在多數據庫環境中,我們將這些遷移腳本組織在單獨的目錄中,例如 db/migration/userdbdb/migration/productdb,以防止版本衝突並確保模式之間的隔離:

以下配置適用於 userdb 數據庫:

-- V1__create_users_table.sql
CREATE TABLE users (
    id BIGINT PRIMARY KEY,
    name VARCHAR(255)
);

以下配置適用於 productdb 數據庫:

-- V1__create_products_table.sql
CREATE TABLE products (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255)
);

這種結構對於避免錯誤至關重要,並且有助於清晰地管理每個數據域的模式變更。

3.7. 單元測試

這裏我們將驗證服務層邏輯和數據庫交互在多數據庫環境中是否正確。該測試確保實體正確地從各自的數據庫中保存和檢索。它還驗證了配置Wiring、Bean初始化以及 Flyway 遷移。

@Test
void givenUsersAndProducts_whenSaved_thenFoundById() {
    User user = new User();
    user.setName("John");
    userRepository.save(user);

    Product product = new Product();
    product.setName("Laptop");
    productRepository.save(product);

    assertTrue(userRepository.findById(user.getId()).isPresent());
    assertTrue(productRepository.findById(product.getId()).isPresent());
}

此測試確保兩個數據庫可以獨立運行,並正確持久化數據。

4. 結論

在本教程中,我們探討了如何使用兩個數據庫配置 Spring Boot,獨立管理 Flyway 遷移,並使用單元測試驗證設置。 這種模式可以輕鬆擴展以支持其他數據庫或數據庫引擎,例如 PostgreSQL 或 MySQL,只需相應地修改 datasource 屬性。

管理 Spring Boot 應用程序中的多個數據庫可能具有挑戰性,尤其是在涉及模式版本控制時。 通過明確定義每個數據源的配置、存儲庫和 Flyway 設置,我們可以清晰地分離關注點並實現平穩的遷移。 這種方法不僅提高了可維護性,而且也與企業應用程序中通常需要的模塊化架構相符。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.