Spring Cloud中如何使用flyway来管理数据库版本!

本文介绍如何在SpringBoot项目中集成Flyway进行数据库版本控制,包括配置依赖、创建SQL脚本、编写测试类等内容。
一、背景

一直以来,在Mybatis中对于手工建库与修改表结构是一个比较遭人诟病的一个话题,今有幸在实际项目中学习了关于利用flyway来构建及管理数据库版本以方便对数据库表及结构的管理操作。

二、Flyway简介

Flyway是一个简单开源数据库版本控制器(约定大于配置),主要提供migrate、clean、info、validate、baseline、repair等命令。它支持SQL(PL/SQL、T-SQL)方式和Java方式,支持命令行客户端等,还提供一系列的插件支持(Maven、Gradle、SBT、ANT等)。

官方网站:https://flywaydb.org/

本文对于Flyway的自身功能不做过多的介绍,读者可以通过阅读官方文档或利用搜索引擎获得更多资料。下面我们具体说说在Spring Boot/Spring Cloud应用中的应用,如何使用Flyway来创建数据库以及结构不一致的检查。

三、配置Flyway

1、引入依赖

在pom.xml中增加flyway的依赖,具体代码如下:

    <!--flyway-->
        <dependency>
            <groupId>org.flywaydb</groupId>
            <artifactId>flyway-core</artifactId>
            <version>5.0.7</version>
        </dependency>
 <!--flyway-spring-test-->
      <dependency>
          <groupId>org.flywaydb.flyway-test-extensions</groupId>
          <artifactId>flyway-spring-test</artifactId>
          <scope>test</scope>
      </dependency>

2、建立数据库文件

按Flyway的规范创建版本化的SQL脚本(规划化可支持无配置,即约定优于配置)。
在工程的src/main/resources目录下创建db目录

在db目录下可创建版本化的SQL脚本V1.0__Base_version.sql(db目录下可再新建目录,非必须在db根目录下创建,如db/mssqlserver/V1/V1.0__admin_init.sql)


其部分内容如下所示:

/*==============================================================*/
/* Table: admin_user                                            */
/*==============================================================*/
DROP TABLE IF EXISTS admin_user ;
CREATE TABLE admin_user (
  id            BIGINT IDENTITY (1, 1) NOT NULL PRIMARY KEY,
  username      NVARCHAR(50)  NULL,
  password      NVARCHAR(250) NULL,
  name          NVARCHAR(50)  NULL,
  mobile        NVARCHAR(20)  NULL,
  email         NVARCHAR(100) NULL,
  enabled       BIT          DEFAULT '1',
  deleted       BIT          DEFAULT '0',
  creator_id    BIGINT       DEFAULT NULL,
  creator       NVARCHAR(50) DEFAULT NULL,
  date_created  DATETIME     DEFAULT NULL,
  modifier_id   BIGINT       DEFAULT NULL,
  modifier      NVARCHAR(50) DEFAULT NULL,
  last_modified DATETIME     DEFAULT NULL
);

3、建立测试类

@RunWith(SpringRunner.class)
@SpringBootTest(classes = AdminApplication.class)
@TestPropertySource(properties = {"spring.profiles.active: test", "flyway.enabled: true"})
@EnableAutoConfiguration
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class, FlywayTestExecutionListener.class})
@Slf4j
public class ApiDAOTest {

    @Autowired
    private ApiDAO apiDAO;

    @FlywayTest
    @Test
    public void apiDAOTest() throws Exception {
        ApiDO apiDO = ApiUtils.fakerApiDO();
        Integer insertRow = apiDAO.insert(apiDO);
        Assertions.assertThat(insertRow).isEqualTo(1);

        Long id = 1L;
        ApiDO result = apiDAO.selectById(id);
        assertThat(result).hasFieldOrPropertyWithValue("id", id);

        Integer apiNumber = apiDAO.deleteById(id);
        assertThat(apiNumber).isEqualTo(1);
    }

}

上述测试类仅为测试类的代码相关代码可忽略,可根据自己的项目建立,这里主要引用的注解有三个需要注意的地方@SpringBootTest、@TestPropertySource、@TestExecutionListeners及@FlywayTest注解,这里使用SpringBootTest注解是为了方便集成测试配置,其他两项配置是指配置文件来源、是否启用Flyway(默认是启用的,配置文件中可增加开关,以便于应用于生产环境中)及配置执行监听服务。

单元测试类实例代码如下:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = AdminApplication.class,properties = "classpath:/application-test.yaml")
@TestPropertySource(properties = { "spring.profiles.active: test", "flyway.enabled: true" })
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class, FlywayTestExecutionListener.class})
@FlywayTest
public class ApiServiceTest {

    /**
     * API接口服务service服务
     */
    @Autowired
    private ApiService apiService;

    /**
     * 测试API接口服务新增
     * @throws Exception
     */
    @Test
    public void insert() throws Exception {
        AdminApiParam apiParam = ApiUtils.fakerApiParam();
        boolean insertSuccess = apiService.insert(apiParam);
        Assertions.assertThat(insertSuccess).isEqualTo(true);
        ApiDO apiDO = new ApiDO();
        apiDO.setName(apiParam.getName());
        EntityWrapper<ApiDO> eWrapper = new EntityWrapper<ApiDO>(apiDO);
        ApiDO result = apiService.selectOne(eWrapper);
        boolean deleteSuccess = apiService.deleteById(result.getId());
        Assertions.assertThat(deleteSuccess).isEqualTo(true);
    }

这里的引入了@TestPropertySource、@ActiveProfiles、@FlywayTest同上一致的注解,前两项为指定配置文件为test配置文件,其中@FlywayTest与@TestExecutionListeners注解主要就是实现数据库表结构的生成与执行数据清理,当执行测试类时会自动将数据库中已有的数据进行清理!

4、配置YAML文件

配置文件application-test.yaml内容如下:

# flyway开关
flyway:
  enabled: true

关于flyway更多配置选项可查询相关flyway API进行查看,另网上很多文章描述需在application的文件中配置Flyway要加载的SQL脚本位置,但在本例中无需配置flyway.locations选项,因为我们采用的是约定大于配置,即使用约定的路径flyway会自动去寻找。

四、测试

启动ApiDAOTest中的AdminApplication即Spring Cloud的主程序,此时即会连接数据库进行数据库表结构的初始化与版本控制,系统会自动在数据库中建立flyway_schema_history用于版本控制的表(注意:此处不建立自己手工在数据库后台建表,因为当手工建立以后缺少flyway表会引出集成测试错误),这时系统就会利用flyway自动完成数据库的构建。当然配置文件中不能缺少spring.datasource的配置内容,要不无法连接数据库。然后通过数据库客户端工具连接数据库即可查看所建立好的数据表结构。


五、总结

到这里为止,本文的内容暂告一段落。由于博文篇幅问题,对于Flyway更细节的使用没有说的太多,本文主要作为敲门砖,帮助和引导正在使用Spring Boot做系统开发的个人或团队在数据库的版本控制上做的更好提供一些思路。至于更深入的应用还请读者自行翻阅官方文档参考和学习。

同时这里需要注意三点:

1、当在使用intellij idea开发工具时请不要将maven project视图中的跳过test禁用,否则将无法正常创建和进行集成与单元测试(如下图箭头所示)。


2、除主程序 AdminApplication启动类以外,ApiDAOTest、ApiServiceTest等测试类也可在主程序未启动时单独进行集成与单元测试,测试类会自动创建对应的数据库表;另上述测试类中如果不引用@FlywayTest或@TestExecutionListeners任一注解的话,都不会自动清理数据库表中的数据,而是直接生成新的数据进行相关集成与单元测试!

3、如果你需要对数据库表结构进行更改,可编写alter语句来完成,让flyway去自动执行,以避免数据库的人为手工操作。

Spring Cloud 项目中集成 Flyway 是一种非常常见的数据库版本管理方式。Flyway 能够帮助你在微服务架构中自动执行数据库迁移脚本(如 DDL 和 DML),确保每个服务的数据库结构与代码版本保持一致。 下面详细介绍如何将 **Flyway** 部署到 **Spring Cloud** 项目中,并提供完整配置示例。 --- ### ✅ 步骤一:添加依赖 在你的 Spring Cloud 微服务模块的 `pom.xml` 中加入 Flyway数据库驱动依赖: ```xml <dependencies> <!-- Spring Boot Starter Web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Spring Boot Starter JDBC 或 JPA --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!-- Flyway Database Migration Tool --> <dependency> <groupId>org.flywaydb</groupId> <artifactId>flyway-core</artifactId> </dependency> <!-- 数据库驱动,以 MySQL 为例 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> </dependencies> ``` > 注意:如果你使用的是 Spring Boot 2.5+,`flyway-core` 会自动配置,无需额外配置类。 --- ### ✅ 步骤二:配置数据源和 Flyway(application.yml) 在 `src/main/resources/application.yml` 中配置数据库连接和 Flyway 相关参数: ```yaml spring: datasource: url: jdbc:mysql://localhost:3306/your_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC username: root password: your_password driver-class-name: com.mysql.cj.jdbc.Driver flyway: enabled: true # 启用 Flyway,默认为 true locations: classpath:db/migration # 迁移脚本路径 baseline-on-migrate: true # 第一次迁移时自动创建 schema_version 表 clean-disabled: true # 生产环境务必禁用 clean 操作 validate-on-migrate: true # 检查脚本是否被修改过 ``` > ⚠️ 安全提示:`clean-disabled: true` 是必须的,防止误删数据库结构。 --- ### ✅ 步骤三:编写数据库迁移脚本 Flyway 要求脚本放在 `src/main/resources/db/migration` 目录下,命名格式为: ``` V{版本号}__{描述}.sql ``` 例如: ``` V1__create_user_table.sql V2__add_email_to_user.sql V3__create_index_on_username.sql ``` 示例脚本内容: **V1__create_user_table.sql** ```sql CREATE TABLE users ( id BIGINT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL UNIQUE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); ``` **V2__add_email_to_user.sql** ```sql ALTER TABLE users ADD COLUMN email VARCHAR(100); ``` > Flyway 会按照版本号顺序自动执行这些脚本,并记录在数据库中的 `flyway_schema_history` 表中。 --- ### ✅ 步骤四:启动应用自动执行迁移 当你启动 Spring Boot 应用时,Flyway 会在容器初始化阶段自动检测并执行未应用的迁移脚本。 ```java @SpringBootApplication public class UserServiceApplication { public static void main(String[] args) { SpringApplication.run(UserServiceApplication.class, args); } } ``` 无需任何额外代码,只要类路径中有 `flyway-core` 且数据源配置正确,Flyway 就会自动工作。 --- ### ✅ 可选:自定义 Flyway 配置(高级用法) 如果需要更精细控制,可以创建一个配置类: ```java @Configuration public class FlywayConfig { @Bean public Flyway flyway(DataSource dataSource) { Flyway flyway = Flyway.configure() .dataSource(dataSource) .locations("classpath:db/migration") .baselineOnMigrate(true) .validateOnMigrate(true) .load(); flyway.migrate(); // 手动触发迁移 return flyway; } } ``` > 注意:手动配置后,Spring Boot 的自动配置将不再生效,需自行管理。 --- ### ✅ 在 Spring Cloud 多服务环境中的最佳实践 1. **每个微服务独立维护自己的数据库迁移脚本** → 避免服务间耦合。 2. **使用 CI/CD 自动部署时确保先运行 Flyway 再启动服务** 3. **生产环境禁止 `flyway.clean()`** → 设置 `flyway.clean-disabled=true` 4. **共享数据库?谨慎!建议通过领域划分避免冲突** 5. **可结合 `@Component` + `ApplicationRunner` 做迁移后校验或通知** --- ### ✅ 常见问题排查 | 问题 | 解决方案 | |------|----------| | 报错 `Validate failed. Migration Checksum mismatch` | 不要修改已执行的 SQL 脚本,应新建版本脚本修复 | | `flyway_schema_history` 表不存在 | 开启 `baseline-on-migrate: true` | | 脚本未执行 | 检查路径是否为 `db/migration`,命名是否符合规范 | --- ### ✅ 总结 FlywaySpring Cloud 中的部署非常简单,只需: 1. 加依赖; 2. 配置数据源; 3. 放 `.sql` 脚本; 4. 启动即自动迁移。 它非常适合微服务架构下的数据库版本控制。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

apicescn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值