使用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的錯誤。html

本文環境

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

知識準備

官方文檔:mysql

解決方案

  1. 新建一個數據庫,並將ddl-auto設置爲create, 而後啓用flyway
  2. 獲得一張flyway須要使用的數據表,並導出爲scheme.sql文件。
  3. 將導出的scheme.sql文件,導入到歷史數據庫中。

啓用flyway

創建flyway數據庫

mysql中創建flyway數據庫。
clipboard.pnggit

加入flyway依賴

pom.xml中加入flywaygithub

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.mengyunzhi.springBootSampleCode</groupId>
    <artifactId>flyway</artifactId>
    <version>1.0</version>
    <packaging>jar</packaging>

    <name>flyway</name>
    <description>在歷史項目上使用flyway作版本遷移控制</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.flywaydb</groupId>
            <artifactId>flyway-core</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

創建升級sql

resources中創建db/migration文件夾,並創建V1.0__init.sql(是__而不是_)。spring

clipboard.png

V1.0__init.sqlsql

# 這是一行註釋,防止文件爲空。

生成數據表

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的歷史數據庫中,將其導入便可。apache

測試

咱們保持數據爲不動,把當前項目模擬爲歷史項目(ddl-auto: update), 更改配置爲:maven

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: //

clipboard.png

-- 重寫 ; 爲 // ,在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更新數據表,成爲了可能。

對於初級軟件工程師的咱們,咱們的需求其實大牛們早就解決了。成功的祕訣即是:與成功者共舞。嘗試看懂、應用官方文檔,今天你行動了嗎?

路漫漫其修遠兮,吾將上下而求索。

河北工業大學夢雲智軟件開發團隊,期待你的加入!

相關文章
相關標籤/搜索