【Spring Cloud 基础设施搭建系列】Spring Cloud Demo项目 使用Flyway管理数据库版本

什么是Flyway

Flyway 是一款开源的数据库版本管理工具,它更倾向于规约优于配置的方式。Flyway 可以独立于应用实现管理并跟踪数据库变更,支持数据库版本自动升级,并且有一套默认的规约,不需要复杂的配置,Migrations 可以写成 SQL 脚本,也可以写在 Java 代码中,不仅支持 Command Line 和 Java API,还支持 Build 构建工具和 Spring Boot 等,同时在分布式环境下能够安全可靠地升级数据库,同时也支持失败恢复等。

Flyway 的特点

Flyway 大受欢迎是因为它具有以下优点:

  • 简单 非常容易安装和学习,同时迁移的方式也很容易被开发者接受。
  • 专一 专注于搞数据库迁移、版本控制而并没有其它副作用。
  • 强大 专为连续交付而设计。让Flyway在应用程序启动时迁移数据库。

使用Flyway管理数据库版本

关于Flyway我就不多介绍了,感兴趣的可以参考文章最下面的参考链接。

我这里直接开始介绍怎么整合Flyway。

Spring Boot 提供了对 Flyway 的自动配置 。使我们可以开箱即用 Flyway 进行数据库版本控制。

  1. 首先我们先加入maven依赖和插件
<dependency>
    <!-- 无需版本号 -->
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-core</artifactId>
</dependency>
  <build>
        <plugins>
            <plugin>
                <groupId>org.flywaydb</groupId>
                <artifactId>flyway-maven-plugin</artifactId>
                <configuration>
                    <url>jdbc:mysql://192.168.99.100:3306/spring_cloud_demo</url>
                    <user>root</user>
                    <password>root</password>
                </configuration>
            </plugin>
        </plugins>
    </build>

添加插件的目的是为了使用Flyway的一些命令、

在这里插入图片描述

可以参考:Flyway提供的六种命令

可以通过mvn flyway:info命令来查看数据库的版本和和需要执行的sql脚本。通过mvn flyway:clean来清空数据库,这条命令对于测试很方便,但是千万要小心生产环境!!!此外,还有一个较常用的命令:mvn flyway:validate可以验证是否所有的sql都已经在数据库上运行完毕了。

  1. 加入flyway配置。
spring:
  flyway:
    # 启用或禁用 flyway
    enabled: true
    # flyway 的 clean 命令会删除指定 schema 下的所有 table, 生产务必禁掉。这个默认值是 false 理论上作为默认配置是不科学的。
    clean-disabled: true
    # SQL 脚本的目录,多个路径使用逗号分隔 默认值 classpath:db/migration
    locations: classpath:db/migration
    #  metadata 版本控制信息表 默认 flyway_schema_history
    table: flyway_schema_history
    # 如果没有 flyway_schema_history 这个 metadata 表, 在执行 flyway migrate 命令之前, 必须先执行 flyway baseline 命令
    # 设置为 true 后 flyway 将在需要 baseline 的时候, 自动执行一次 baseline。
    baseline-on-migrate: true
    # 指定 baseline 的版本号,默认值为 1, 低于该版本号的 SQL 文件, migrate 时会被忽略
    baseline-version: 1
    # 字符编码 默认 UTF-8
    encoding: UTF-8
    # 是否允许不按顺序迁移 开发建议 true  生产建议 false
    out-of-order: false
    # 需要 flyway 管控的 schema list,这里我们配置为spring_cloud_demo  缺省的话, 使用spring.datasource.url 配置的那个 schema,
    # 可以指定多个schema, 但仅会在第一个schema下建立 metadata 表, 也仅在第一个schema应用migration sql 脚本.
    # 但flyway Clean 命令会依次在这些schema下都执行一遍. 所以 确保生产 spring.flyway.clean-disabled 为 true
    schemas: spring_cloud_demo
    # 执行迁移时是否自动调用验证   当你的 版本不符合逻辑 比如 你先执行了 DML 而没有 对应的DDL 会抛出异常
    validate-on-migrate: true
  1. 在resource目录下创建db/migration目录添加sql脚本
use `spring_cloud_demo`;

create table MEMBERS (
    id integer not null auto_increment,
    create_by varchar(255),
    create_date datetime,
    update_by varchar(255),
    update_date datetime,
    jpa_version bigint,
    member_name varchar(20) not null,
    primary key (id)
)ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;

INSERT INTO spring_cloud_demo.MEMBERS (id, create_by, create_date, update_by, update_date, jpa_version, member_name) VALUES (1, 'admin', '2019-11-02 06:52:05', 'system', '2019-11-02 06:52:17', 1, 'system');

请注意命名规则。脚本名称为 V1.0.1__insert_init_member_data.sql

Flyway的命名规范如下:以V开头,.sql结尾,版本号可以使用.或者_,版本号和描述之间用两个下划线__分开。

  1. 启动项目

启动项目之后发现报错java.sql.SQLException: sql injection violation

Caused by: java.sql.SQLException: sql injection violation, comment not allow : CREATE TABLE `spring_cloud_demo`.`flyway_schema_history` (
    `installed_rank` INT NOT NULL,
    `version` VARCHAR(50),
    `description` VARCHAR(200) NOT NULL,
    `type` VARCHAR(20) NOT NULL,
    `script` VARCHAR(1000) NOT NULL,
    `checksum` INT,
    `installed_by` VARCHAR(100) NOT NULL,
    `installed_on` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `execution_time` INT NOT NULL,
    `success` BOOL NOT NULL,
    -- Add the primary key as part of the CREATE TABLE statement in case `innodb_force_primary_key` is enabled
    CONSTRAINT `flyway_schema_history_pk`PRIMARY KEY (`installed_rank`)
) ENGINE=InnoDB
	at com.alibaba.druid.wall.WallFilter.checkInternal(WallFilter.java:800) ~[druid-1.1.10.jar:1.1.10]
	at com.alibaba.druid.wall.WallFilter.check(WallFilter.java:780) ~[druid-1.1.10.jar:1.1.10]
	at com.alibaba.druid.wall.WallFilter.statement_execute(WallFilter.java:413) ~[druid-1.1.10.jar:1.1.10]
	at com.alibaba.druid.filter.FilterChainImpl.statement_execute(FilterChainImpl.java:2956) ~[druid-1.1.10.jar:1.1.10]
	at com.alibaba.druid.filter.FilterAdapter.statement_execute(FilterAdapter.java:2473) ~[druid-1.1.10.jar:1.1.10]
	at com.alibaba.druid.filter.FilterEventAdapter.statement_execute(FilterEventAdapter.java:188) ~[druid-1.1.10.jar:1.1.10]
	at com.alibaba.druid.filter.FilterChainImpl.statement_execute(FilterChainImpl.java:2956) ~[druid-1.1.10.jar:1.1.10]
	at com.alibaba.druid.proxy.jdbc.StatementProxyImpl.execute(StatementProxyImpl.java:147) ~[druid-1.1.10.jar:1.1.10]
	at com.alibaba.druid.pool.DruidPooledStatement.execute(DruidPooledStatement.java:619) ~[druid-1.1.10.jar:1.1.10]
	at org.flywaydb.core.internal.jdbc.JdbcTemplate.executeStatement(JdbcTemplate.java:235) ~[flyway-core-5.2.3.jar:na]
	at org.flywaydb.core.internal.sqlscript.StandardSqlStatement.execute(StandardSqlStatement.java:42) ~[flyway-core-5.2.3.jar:na]
	at org.flywaydb.core.internal.sqlscript.DefaultSqlScriptExecutor.executeStatement(DefaultSqlScriptExecutor.java:189) ~[flyway-core-5.2.3.jar:na]
	... 30 common frames omitted

原因是Flyway通过 SQL 脚本来执行数据库的建立与更新。当同时集成了 Druid 和 Flyway 之后,Druid 的 wall 防火墙极可能直接干预 SQL 脚本的操作,继而导致 Flyway 执行中断。

我的解决方法就是去掉filters:wall。

还有一点要注意的就是需要把我们hibernate的ddl-auto设置为ddl-auto: none

之后重新启动就可以了。

启动完毕之后我们用flyway:info就可以看到我们的脚本已经执行状态是成功了。

[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building cloud-service-member 1.0
[INFO] ------------------------------------------------------------------------
[WARNING] The POM for com.cc.cloud:cloud-test-common:jar:1.0 is invalid, transitive dependencies (if any) will not be available, enable debug logging for more details
[INFO] 
[INFO] --- flyway-maven-plugin:5.2.3:info (default-cli) @ cloud-service-member ---
[INFO] Flyway Community Edition 5.2.3 by Boxfuse
[INFO] Database: jdbc:mysql://192.168.99.100:3306/spring_cloud_demo (MySQL 8.0)
[INFO] Schema version: 1.0.1
[INFO] 
[INFO] +-----------+---------+-------------------------+------+---------------------+---------+
| Category  | Version | Description             | Type | Installed On        | State   |
+-----------+---------+-------------------------+------+---------------------+---------+
| Versioned | 1.0.1   | insert init member data | SQL  | 2019-11-10 21:09:48 | Success |
+-----------+---------+-------------------------+------+---------------------+---------+

使用Flyway改造我们的集成测试

这里我直接给出我的配置文件,想知道具体怎么搭建集成测试环境的可以看我之前的博文。

spring:
  datasource:
    druid:
      # jdbc:h2:mem:指定databaseName; 内存模式
      # DB_CLOSE_DELAY=-1 关闭连接后数据库将被清空,适合测试环境
      # MODE=MYSQL 兼容模式为MYSQL
      # DB_CLOSE_ON_EXIT=FALSE	 VM存在时不关闭数据库
      url: jdbc:h2:mem:member_service_db;MODE=MYSQL;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
      username: sa
      password: sa
      driver-class-name: org.h2.Driver
    platform: h2
    # schema: classpath:schema.sql //程序运行时,使用schema.sql来创建数据库中的表
    # data: classpath:/db/init-data.sql # 程序运行时,使用db/init-data.sql来创建初始数据
  jpa:
    database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
    database: h2
    show-sql: true
    hibernate:
      ddl-auto: none # create-drop 每次加载hibernate时根据model类生成表,但是sessionFactory一关闭,表就自动删除。
    properties:
      hibernate:
        show_sql: true # 操作数据库时显示sql语句
        use_sql_comments: true # SQL 语句中输出便于调试的注释信息
        format_sql: true
        dialect: org.hibernate.dialect.MySQL5InnoDBDialect
        jdbc:
          time_zone: UTC
  flyway:
    # 启用或禁用 flyway
    enabled: true
    # flyway 的 clean 命令会删除指定 schema 下的所有 table, 生产务必禁掉。这个默认值是 false 理论上作为默认配置是不科学的。
    clean-disabled: true
    # SQL 脚本的目录,多个路径使用逗号分隔 默认值 classpath:db/migration
    locations: classpath:test/db/migration
    #  metadata 版本控制信息表 默认 flyway_schema_history
    table: flyway_schema_history
    # 如果没有 flyway_schema_history 这个 metadata 表, 在执行 flyway migrate 命令之前, 必须先执行 flyway baseline 命令
    # 设置为 true 后 flyway 将在需要 baseline 的时候, 自动执行一次 baseline。
    baseline-on-migrate: true
    # 指定 baseline 的版本号,默认值为 1, 低于该版本号的 SQL 文件, migrate 时会被忽略
    baseline-version: 1
    # 字符编码 默认 UTF-8
    encoding: UTF-8
    # 是否允许不按顺序迁移 开发建议 true  生产建议 false
    out-of-order: false
    # 这里的schemas需要使用PUBLIC,使用H2 默认的schema,防止找不到报错Caused by: org.h2.jdbc.JdbcSQLException: Table “xxxx” not found
    schemas: PUBLIC
    # 执行迁移时是否自动调用验证   当你的 版本不符合逻辑 比如 你先执行了 DML 而没有 对应的DDL 会抛出异常
    validate-on-migrate: true
  h2: # 开启h2的控制台
    console:
      enabled: true
      path: /console
      settings:
        trace: false
        web-allow-others: true
  cloud:
    bus:
      enabled: false # 关闭Spring Cloud Bus,停止连接RabbitMQ
    config:
      enabled: false # disable config
      discovery:
        enabled: false # disable config
    discovery: # disable eureka
      enabled: false
eureka:
  client:
    enabled: false # disable eureka

这里唯一值得注意的就是schemas: PUBLIC,使用的是H2 默认的schema,防止找不到报错Caused by: org.h2.jdbc.JdbcSQLException: Table “xxxx” not found

然后还有添加sql脚本

create table MEMBERS (
    id integer not null auto_increment,
    create_by varchar(255),
    create_date datetime,
    update_by varchar(255),
    update_date datetime,
    jpa_version bigint,
    member_name varchar(20) not null,
    primary key (id)
)ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;

INSERT INTO MEMBERS(id, create_by, create_date, update_by, update_date, jpa_version, member_name) VALUES (1, 'admin', '2019-11-02 06:52:05', 'system', '2019-11-02 06:52:17', 1, 'system');

还有一定要注意的是sql脚本的路径一定要对,是test/db/migration,不是test.db.migration,在IDEA显示的时候可能都一样,但是要注意真实路径下的文件夹路径是不是对的。不然会报找不到sql脚本。

最后是运行测试。

在这里插入图片描述

参考

Flyway的使用

快速学会像Git一样管理数据库业务版本变更

轻松上手数据库版本管理工具Flyway

Spring Boot中使用Flyway来管理数据库版本

Flyway 简单入门教程

Flyway官网

Flyway提供的六种命令

内存中的Spring boot flyway H2:引起:org.h2.jdbc.JdbcSQLException:表“xxxx”未找到; SQL语句:

Spring boot + flyway + H2 in memory :Caused by: org.h2.jdbc.JdbcSQLException: Table “xxxx” not found; SQL statement:

源代码

https://gitee.com/cckevincyh/spring-cloud-demo/tree/flyway/

发布了647 篇原创文章 · 获赞 816 · 访问量 98万+

猜你喜欢

转载自blog.csdn.net/cckevincyh/article/details/103003162
今日推荐