提示:本文中,我们只给了部分示例代码。如果你需要完整的代码,请点击: 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
知识准备
官方文档:
解决方案
- 新建一个数据库,并将
ddl-auto
设置为create
, 然后启用flyway
。 - 得到一张
flyway
需要使用的数据表,并导出为scheme.sql
文件。 - 将导出的
scheme.sql
文件,导入到历史数据库中。
启用flyway
建立flyway
数据库
在mysql
中建立flyway
数据库。
加入flyway
依赖
pom.xml
中加入flyway
<?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
(是__
而不是_
)。
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
起动应用,此时,将在数据库中,生成一张数据表。
导出数据表结构
在数据表上右键 -> 转存为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: //
-- 重写 ; 为 // ,在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 ;
测试
- 删除原来生成的数据表
flyway_schema_history
。 - 启动项目
项目正常启动,并生成了flyway
的数据表。而且,该数据表中,添加了1.0版本的初始化文件。成功!
我们接着测试:
- 删除原来生成的数据表
flyway_schema_history
- 将
schema.sql
更名为schema1.sql
- 启动项目
报没有找到历史数据表的错误,不错,这正是我们期待的,这说明,生成flyway
所需要的数据表,的确是schema.sql
的功劳。
扩展
在进行开发时,如果我们使用的为h2
等嵌入式数据库,每次数据表都重新生成的话,需要禁用自动执行schema1.sql
,即需要将initialization-mode:
设置为none
。
总结
我们通过查看官方文档,结合mysql
创建函数的知识,解决了在历史表中,自动生成flyway
所需要的数据表的目标。从而使项目上线后,使用flyway
更新数据表,成为了可能。
对于初级软件工程师的我们,我们的需求其实大牛们早就解决了。成功的秘诀便是:与成功者共舞。尝试看懂、应用官方文档,今天你行动了吗?
路漫漫其修远兮,吾将上下而求索。
河北工业大学梦云智软件开发团队,期待你的加入!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。