使用flyway对历史数据表进行版本迁移

提示:本文中,我们只给了部分示例代码。如果你需要完整的代码,请点击: https://github.com/mengyunzhi/springBootSampleCode/tree/master/flyway

WHY TO DO

在使用flyway的版本迁移功能时,如果我们并不是在项目之初就启用flyway的话,那么在有历史数据的情况下,启用flyway后,由于数据库中,并不存在flyway所依赖的库,所以将会出现:set baselineOnMigrate to true to initialize the schema history table的错误。

本文环境

java:1.8 + spring-boot:2.0.3.RELEASE + mysql:5.6

知识准备

官方文档:

解决方案

  1. 新建一个数据库,并将ddl-auto设置为create, 然后启用flyway
  2. 得到一张flyway需要使用的数据表,并导出为scheme.sql文件。
  3. 将导出的scheme.sql文件,导入到历史数据库中。

启用flyway

建立flyway数据库

mysql中建立flyway数据库。
使用flyway对历史数据表进行版本迁移_第1张图片

加入flyway依赖

pom.xml中加入flyway



    4.0.0

    com.mengyunzhi.springBootSampleCode
    flyway
    1.0
    jar

    flyway
    在历史项目上使用flyway做版本迁移控制

    
        org.springframework.boot
        spring-boot-starter-parent
        2.0.3.RELEASE
         
    

    
        UTF-8
        UTF-8
        1.8
    

    
        
            org.springframework.boot
            spring-boot-starter-data-jpa
        
        
            org.flywaydb
            flyway-core
        

        
            mysql
            mysql-connector-java
            runtime
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    



建立升级sql

resources中建立db/migration文件夹,并建立V1.0__init.sql(是__而不是_)。

使用flyway对历史数据表进行版本迁移_第2张图片

V1.0__init.sql

# 这是一行注释,防止文件为空。

生成数据表

spring:
  jpa:
    hibernate:
      ddl-auto: create
  datasource:
    username: root
    password:
    url: jdbc:mysql://127.0.0.1/flywayDemo?useUnicode=true&characterEncoding=utf-8

起动应用,此时,将在数据库中,生成一张数据表。

clipboard.png

导出数据表结构

在数据表上右键 -> 转存为sql文件 -> 仅结构。然后我们在需要使用flyway的历史数据库中,将其导入即可。

测试

我们保持数据为不动,把当前项目模拟为历史项目(ddl-auto: update), 更改配置为:

spring:
  jpa:
    hibernate:
      ddl-auto: update
  datasource:
    username: root
    password:
    url: jdbc:mysql://127.0.0.1/flywayDemo?useUnicode=true&characterEncoding=utf-8

应用成功启动,未报错。

优化方案

上述方案,是可行的,但不够自动化。我们期待自动化的解决数据表的升级问题,而不是手工去做1,2,3,4..项操作。原因很简单,当我们进行数据升级时,心情大都会比较紧张,就怕出错。但越紧张就越容易出错,如果我们今天手动改一点,记本上,明天手动改一点,再记本上。系统一升级,手工进行1-12项改动,难免就会发生错误。所以,我们要避免手动进行升级可能会发生错误的尴尬。

下面,我们启用spring boot在初始化数据方法,在初始化数据时,增加一个函数。在函数中实现:如果有了flyway的数据表,则跳过。如果没有flyway的数据表,则执行语句生成数据表。

启用数据初始化

spring:
  jpa:
    hibernate:
      ddl-auto: update
  datasource:
    username: root
    password:
    url: jdbc:mysql://127.0.0.1/flywayDemo?useUnicode=true&characterEncoding=utf-8
#    设置数据初始化模式为:always
    initialization-mode: always     
#    设置 ; 的重写符号
    separator: //

使用flyway对历史数据表进行版本迁移_第3张图片

-- 重写 ; 为 // ,在spring中,注释掉下面一行,应该我们在配置文件中的 separator: // 便是起的该作用
-- DELIMITER //
-- 如果存在函数,则先删除
DROP PROCEDURE IF EXISTS `FUN20180706` //
-- 定义函数FUN20180706
CREATE PROCEDURE `FUN20180706` ()
    BEGIN
        DECLARE hasDataTable INT;
        SELECT count(*) INTO hasDataTable FROM information_schema.tables WHERE (table_schema = 'flywayDemo') AND (table_name= 'flyway_schema_history');
        IF hasDataTable = 0 THEN
           CREATE TABLE `flyway_schema_history` (
              `installed_rank` int(11) NOT NULL,
              `version` varchar(50) DEFAULT NULL,
              `description` varchar(200) NOT NULL,
              `type` varchar(20) NOT NULL,
              `script` varchar(1000) NOT NULL,
              `checksum` int(11) DEFAULT NULL,
              `installed_by` varchar(100) NOT NULL,
              `installed_on` timestamp NOT NULL DEFAULT current_timestamp(),
              `execution_time` int(11) NOT NULL,
              `success` tinyint(1) NOT NULL,
              PRIMARY KEY (`installed_rank`),
              KEY `flyway_schema_history_s_idx` (`success`)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
          SET FOREIGN_KEY_CHECKS = 1;
        END IF;
    END
//

-- 调用函数
CALL FUN20180706() //
-- 恢复重写的;,以免影响其它的function
-- DELIMITER ;

测试

  1. 删除原来生成的数据表flyway_schema_history
  2. 启动项目

项目正常启动,并生成了flyway的数据表。而且,该数据表中,添加了1.0版本的初始化文件。成功!

我们接着测试:

  1. 删除原来生成的数据表flyway_schema_history
  2. schema.sql更名为schema1.sql
  3. 启动项目

clipboard.png

报没有找到历史数据表的错误,不错,这正是我们期待的,这说明,生成flyway所需要的数据表,的确是schema.sql的功劳。

扩展

在进行开发时,如果我们使用的为h2等嵌入式数据库,每次数据表都重新生成的话,需要禁用自动执行schema1.sql,即需要将initialization-mode:设置为none

总结

我们通过查看官方文档,结合mysql创建函数的知识,解决了在历史表中,自动生成flyway所需要的数据表的目标。从而使项目上线后,使用flyway更新数据表,成为了可能。

对于初级软件工程师的我们,我们的需求其实大牛们早就解决了。成功的秘诀便是:与成功者共舞。尝试看懂、应用官方文档,今天你行动了吗?

路漫漫其修远兮,吾将上下而求索。

河北工业大学梦云智软件开发团队,期待你的加入!

你可能感兴趣的:(flyway,spring)