Flyway:数据库表版本管理,与springboot集成

目录

一、摘要

二、概览

三、Flyway工作步骤

四、与springboot集成

        4.1 加入依赖

        4.2 添加配置

        4.3 添加SQL

        4.4 添加启动类

        4.5 验证结果

        4.6 注意事项

五、局限性

        5.1 版本号冲突

        5.2 执行顺序


一、摘要

        我们开发或升级项目会碰到很多数据有关问题,比如:这个环境找不到原始的DDL记录、这个环境是否运行了最新的SQL、这个环境运行了哪些SQL、每次更新发版需要先写脚本更新SQL再更新应用、对于老旧项目数据升级或迁移异常困难...

        针对这些问题,我们都需要需要一个记录并运行SQL的工具。我们可以手动开发一个工具,用数据表记录项目变更运行的每句SQL,再和项目特定SQL目录下的SQL语句对比,然后再执行那些未执行过的SQL。当然,目前也有这种开源的SQL版本工具,这就是Flyway。

        当然Flyway并不是很好,比如SQL执行顺序以及版本号小的不执行会有很多问题。

二、概览

        Flyway是个数据库版本管理工具,但我觉得它更像是个SQL版本管理工具。它提供命令行和Java API用于管理数据库表,主要通过项目SQL与数据库里记录运行过的SQL对比来执行SQL,以保持各个环境的数据库表是一致的。其官方文档地址为:Documentation - Flyway by Redgate • Database Migrations Made Easy. 

三、Flyway工作步骤

        1、项目启动,它会连接数据库并寻找一个名为flyway_schema_history的历史记录表,若找不到历史记录表则会创建它。

        2、Flyway扫描文件系统或应用程序类路径(默认为:classpath:db/migration)下的SQL文件,并与历史记录表里的执行过的SQL记录对比,若项目的SQL与执行过的SQL不一致,则报错,项目停止运行。

        3、若校验通过,则将版本号(版本号在SQL文件名中指定)大于历史记录表里的最大版本号的SQL文件按从小到大顺序运行。

四、与springboot集成

        4.1 加入依赖

        具体pom依赖如下:

   <dependencies>
        <dependency>
            <groupId>org.flywaydb</groupId>
            <artifactId>flyway-core</artifactId>
            <version>6.5.7</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.7.9</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.2</version>
        </dependency>
    </dependencies>

        注意不要选太高版本的flyway-core,高版本的flyway-core兼容性不太好,实测9.16.1版本会报异常: java.lang.NoSuchMethodError: org.flywaydb.core.api.configuration.FluentConfiguration.ignoreMissingMigrations(Z)Lorg/flywaydb/core/api/configuration/FluentConfiguration;

        4.2 添加配置

server:
  port: 9090
spring:
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher
  application:
    name: boot-flyway
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test?characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&allowMultiQueries=true
    username: root
    password: root
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8
    serialization:
      write-dates-as-timestamps: false
  # flyway配置
  flyway:
    # 是否启用flyway
    enabled: true
    # 编码格式,默认UTF-8
    encoding: UTF-8
    # 迁移sql脚本文件存放路径,默认db/migration
    locations: classpath:db,classpath:db/alarm,classpath:db/workflow
    # 迁移sql脚本文件名称的前缀,默认V
    sql-migration-prefix: V
    # 迁移sql脚本文件名称的分隔符,默认2个下划线__
    sql-migration-separator: __
    # 前缀和分隔符之间就是版本号,版本号可以用.或_分隔,比如V20230403__add_user.sql、V2023.4.3__add_user.sql、V2023_4_3__add_user.sql的版本号分别是:20230403、2023.4.3、2023_4_3
    # 迁移sql脚本文件名称的后缀
    sql-migration-suffixes: .sql
    # 迁移时是否进行校验,默认true
    validate-on-migrate: true
    # 当迁移发现数据库非空且存在没有元数据的表时,自动执行基准迁移,新建schema_version表
    baseline-on-migrate: true

mybatis-plus:
  mapper-locations: classpath:/mapper/**/*Mapper.xml
  type-aliases-package: com.longqi.boot.flyway.entity.domain
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

        4.3 添加SQL

        在指定位置添加SQL文件,上面配置了三个位置,因此三个位置都可以添加SQL,但是,所有SQL文件的版本号不能相同!

注意SQL的命名规则,SQL文件有执行一次和重复执行两种。SQL命名规则如下:

1、执行一次的SQL:文件名以V开头,格式为 V+版本号+双下划线+文件描述+后缀。其中版本号可以使用“.”或“_”分隔开。比如V1.2_20230404__update_model.sql,其中1.2_20230404就是版本号,update_model就是描述。

2、可以重复执行的SQL:文件名以R开头,其它和上面执行一次的SQL类似,执行优先级比执行一次的SQL低。

        4.4 添加启动类

package com.longqi.boot.flyway;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @Description TODO
 * @Author LongQi
 * @Date 2021/6/20 12:01
 */
@SpringBootApplication
@MapperScan(basePackages = {"com.longqi.boot.flyway.dao"})
public class FlywayApplication {

    public static void main(String[] args) {
        SpringApplication.run(FlywayApplication.class, args);
    }

}

启动类就是普通的springboot启动类,无需做任何特殊处理,Flyway会自动读取spring.flyway相关的配置以及校验运行SQL脚本。

        4.5 验证结果

        启动后数据库如下:

 

   可以看到,运行了SQL,flyway的历史记录表就有记录,然后SQL也都是运行成功。

        4.6 注意事项

        应用一般不会出问题,但SQL需要注意以下几点:

1、历史SQL一旦运行后,不能修改,否则校验不通过,会抛异常导致应用无法启动!

2、SQL的版本号不能相同,否则校验不通过,会抛异常导致应用无法启动!

3、SQL的语句运行不能报错,否则运行SQL错误,会抛异常导致应用无法启动!

4、对于小于数据库最大版本号的SQL文件,是不会执行的!比如执行了0.03版本的SQL,后续添加了0.02_update版本的SQL,重新启动是不会执行0.02_update版本的SQL的!

        SQL和应用已经牢牢的绑在一起了,SQL校验或运行出问题,都是会导致应用无法启动!且SQL对版本号有相当大的限制。生产环境都需要重视。

五、局限性

        个人使用过程中,发现这个框架在每个应用有一个单独数据库的情况下很好使用,但对于目前微服务盛行的年代就不太好使了。

        5.1 版本号冲突

        多个微服务共用一个数据库很常见,甚至不同的微服务由不同小组完成,而每个微服务都集成Flyway的话,可能会导致SQL版本号冲突,当然,各微服务的版本号冲突之类的也有解决办法,规范各微服务的SQL版本号命名即可。

        5.2 执行顺序

        我们知道,Flyway是不会执行比SQL最大版本号小的SQL文件的。而微服务共同发布又要一个版本运行多个SQL,这里只所以运行多个,是因为有些产品各微服务需要拆开卖给客户,因此,SQL不能集中在一起执行。

        这里举例说明,比如某产品发布V1.2版,微服务A和微服务B的SQL分别为V1.2_A和V1.2_B,若上线时,A服务先启动运行还好,后续B服务启动运行判断 V1.2_B>V1.2_A,则V1.2_B可以执行。若是B服务先启动,A服务后启动就遭了,V1.2_A<V1.2_B,这个V1.2_A的SQL是不会执行的!

        Flyway的设计者少考虑了微服务一起发版需要运行多个SQL的问题,有如下几种方法解决:

1、上线的启动脚本可以定义好启动顺序,上一个服务心跳检测成功后再进行启动下一个服务。

2、直接不用Flyway,自己写个类似Flyway的框架即可,再加个应用名判断,同应用名才有版本号大小判断执行SQL。

3、改造Flyway,可以给它创建表时加入应用名字段,插入数据以及判断都加上应用名判断,逻辑和上面类似,同应用名才有版本号大小判断执行SQL。

4、换用别的类似Flyway的框架。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

时间在手上,需要抓住

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

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

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

打赏作者

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

抵扣说明:

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

余额充值