Flyway的第一次认识

1.  引言

想到要管理数据库的版本,是在实际产品中遇到问题后想到的一种解决方案,当时各个环境的数据库乱作一团,没有任何一个人(开发、测试、维护人员)能够讲清楚当前环境下的数据库是哪个版本,与哪个版本的应用相匹配,如何升级到与新版本的应用相匹配。

想到管理数据库版本时,先是心底形成了一个初步的解决方案,大致是通过数据库中的某张表来记录数据库表结构的历次更新与对应版本,在每次数据库表结构调整时除了提供库表更新sql ,还必须提供更新记录与对应版本的sql,以帮助维护数据库版本信息,并在遇到问题时提供相关的排查依据。

后来据此思路在网络上搜索了一把,结果搜到Liquibase (另一款开源数据库版本管理工具)。在学习了解Liquibase 的时候,经高手介绍又了解到了Flyway 这个项目的存在。经过一番了解,最后我们选择了Flyway ,主要原因是Flyway 支持sql 脚本,而Liquibase 只支持XML 方式的数据库表结构定义,虽然在新的版本中号称在XML的数据库表结构定义方式中支持了sql 脚本。

虽然Flyway 的中文文档近乎为零,英文文档也凤毛麟角,但它却是我们最理想的数据库版本管理工具,它不但支持sql 脚本,还支持Java 代码直接操作数据库(在版本升级时做数据迁移相当有用),有Maven 插件,支持命令行(我们的平台数据库有部分由C 语言项目管理),而且在Spring 框架的配合下,很容易就能实现应用启动时自动检查并升级数据库的功能。

2.  什么是Flyway

Flyway 是独立于数据库的应用、管理并跟踪数据库变更的数据库版本管理工具。

Flyway 的项目主页是 http://flywaydb.org/)(最近才迁移到这个主页,之前一直在googlecode 下管理http://code.google.com/p/flyway/),在项目的主页上可以看到Flyway 与几款主流数据库版本管理工具的特性对比列表。

3.  为什么使用Flyway

3.1. 我们遇到的问题

我们遇到的问题(以下内容来自Flyway 的一些英文文档,从中抽取出来的我们也遇到的一些主要问题):

  • 不同的开发人员在开发产品特性时,都有可能更新数据库(添加新表,新的约束等)。当开发人员完成工作并提交代码时,代码会被合并到主分支并在测试服务器上执行单元测试与集成测试。我们在哪个环节来执行数据库的更新操作呢?由QA 部门手工执行sql 脚本?或者我们开发一断程序自动执行数据库更新?以什么顺序来执行这些更新脚本?这些问题同样存在于生产环境。
  • 我们的产品部署在不同的客户服务器上,以及很多的测试、联调、实验局、销售环境上。不同的客户和测试环境上都部署着不同版本的产品。当他们需要升级他们的产品到新的版本时,我们不仅需要让他们的管理员可以升级产品到新的版本,同时需要保留他们的已有数据。在升级产品的步骤中,我们清楚地知道客户数据库的当前版本,以及需要在该数据库上执行哪些数据库更新脚本,来更新数据库表结构与数据库中已存在的数据。当升级完成时,数据库表结构及数据应当与升级后的产品版本保持一致。
  • 有的时候,我们需要通过代码(Java )来维护一些已存在的数据,如通过代码来维护blob 类型的用户头像数据。
  • 当升级失败时(比如在升级过程中出现网络连接失败),我们应当支持对失败进行修复。

3.2. Flyway 的特性

  • 自动升级(自动发现更新项):Flyway 会将任意版本的数据库升级到最新版本。Flyway 可以脱离JVM 环境通过命令行执行,可以通过Ant 脚本执行,通过Maven 脚本执行(这样就可以在集成环境自动执行),并且可以在应用中执行(比如在应用启动时执行)。
  • 规约优于配置:Flyway 有一套默认的规约,所以不需要修改任何配置就可以正常使用。
  • 既支持SQL 脚本,又支持Java 代码:可以使用SQL 脚本执行数据库更新,也可以使用Java 代码来进行一些高级数据升级操作。
  • 高可靠性:在集群环境下进行数据库升级是安全可靠的。
  • 支持清除已存在的库表结构:Flyway 可以清除已存在的库表结构,可以从零开始搭建您的库表结构,并管理您的数据库版本升级工作。
  • 支持失败修复。新的2.0 版本提供了repair 功能,用于解决数据库更新操作失败问题。

结合我们遇到的问题,与Flyway 所提供的特性,我们认为Flyway 是比较适合于我们的一款数据库版本管理工具。

4.  如何使用Flyway

使用Flyway ,我们需要准备Flyway 将要执行的数据库脚本(Flyway 支持sql 脚本与java 代码,这里认为在Flyway下执行数据库更新操作的java 代码也是一种数据库脚本),然后通过Flyway 提供的几种不同运行方式来执行这些脚本。(以下配置参数说明基于Flyway 1.7 版本,新的2.0 版本在配置参数上有不少变动,与下面的介绍会有不少出入,以下说明仅供参考)

4.1. 数据库脚本

Flyway 的主要任务是管理数据库的版本更新,在Flyway 中称每次数据库更新为一个migration ,为了更顺口,我们下面称之为数据库脚本。Flyway 支持SQL-based migrations 和Java-based migrations 。

Flyway 支持的数据库脚本有sql 脚本与java 代码,sql 脚本即普通的sql 脚本,包含创建数据库、表,更新库表结构,数据插入、更新、删除等sql 语句,java 代码则是通过一个有效的数据源,使用java 语言来进行数据库的操作,这里针对的读者是对数据库操作有一定熟悉程度的群体,不再详细讲解如何编写数据库脚本。

Flyway 的sql 脚本与java 代码都遵循以下默认规约:

4.1.1.  Flyway 默认规约

  • SQL 脚本文件默认位置是项目的源文件夹下的db/migration  目录。
  • Java 代码默认位于db.migration  包。
  • SQL 脚本文件及Java 代码类名必须遵循以下命名规则:V<version>[_<SEQ>][__description] 。版本号的数字间以小数点(. )或下划线(_ )分隔开,版本号与描述间以连续的两个下划线(__ )分隔开。如V1_1_0__Update.sql 。Java 类名规约不允许存在小数点,所以Java 类名中版本号的数字间只能以下划线进行分隔。

4.2. Flyway 的几种运行方式

本章主要讲解我们常用的三种Flyway 的执行方式,Flyway 除了提供这三种执行方式外,还提供Ant 任务方式的执行方式,有兴趣的同学可以去官方网站获取相关信息,这里不进行描述。

4.2.1.  命令行方式

通过命令行方式运行Flyway ,需要下载flyway-commandline 版本并解压到本地,然后flyway (Windows 下flyway.cmd ,Linux 下flyway.sh )命令执行Flyway 相关操作。

下图是flyway-commandline-1.7 解压后的目录结构:

命令行方式的特点与规约

  • 无需安装JVM ,Maven ,Ant
  • 默认读取conf/flyway.properties 中的配置信息,如果在命令行中指定参数,命令行中指定的参数将覆盖配置文件中的配置
  • 还可以通过参数-configFlie=myFlyway.properties 来重新指定flyway 配置文件,可以通过-configFileEncoding=GBK 来指定配置文件的编码格式
  • 可以将打包好的java 迁移文件放到jars/  目录下让flyway 可以找到并运行
  • 数据库驱动包(jar )放到jars/  目录下
  • sql 脚本文件放到sql/  目录中

命令行方式运行的配置及使用方法

  1. 修改conf/flyway.properties  配置文件
  2. 拷贝数据库jdbc  驱动jar  到jars/  目录
  3. 在sql/  目录下创建配置好的sql  脚本文件目录路径,如flyway 默认的sql  文件路径为db/migration ,我们就需要在sql/  目录下创建/db/migration  目录结构
  4. 将数据库维护脚本放到创建好的sql  脚本文件目录中(维护脚本文件名需要遵循命名规范)
  5. 在命令行执行命令(从flyway 安装目录开始执行)flyway init (初始化Flyway metadata )、flyway migrate(执行Flyway 升级操作)、flyway validate (校验Flyway 数据正确性)

4.2.2.  Maven 插件

配置Maven 插件

Xml代码

  1. <plugin>
  2. <groupId>com.googlecode.flyway</groupId>
  3. <artifactId>flyway-maven-plugin</artifactId>
  4. <version>1.7</version>
  5. <dependencies>
  6. <dependency>
  7. <groupId>mysql</groupId>
  8. <artifactId>mysql-connector-java</artifactId>
  9. <version>${mysql.connector.version}</version>
  10. </dependency>
  11. </dependencies>
  12. <configuration>
  13. <driver>com.mysql.jdbc.Driver</driver>
  14. <url>jdbc:mysql://localhost/flywaydemo?useUnicode=true&amp;characterEncoding=utf-8</url>
  15. <user>root</user>
  16. <password></password>
  17. <!-- 设置接受flyway进行版本管理的数据库,多个数据库以逗号分隔 -->
  18. <schemas>flywaydemo</schemas>
  19. <!-- 设置存放flyway metadata数据的表名 -->
  20. <table>schema_version</table>
  21. <!-- 设置flyway扫描sql升级脚本、java升级脚本的目录路径或包路径 -->
  22. <locations>
  23. <location>flyway/migrations</location>
  24. <location>com.kedacom.flywaydemo.migrations</location>
  25. </locations>
  26. <!-- 设置sql脚本文件的编码 -->
  27. <encoding>UTF-8</encoding>
  28. <!-- 设置执行migrate操作之前的validation行为 -->
  29. <validationMode>ALL</validationMode>
  30. <!-- 设置当validation失败时的系统行为 -->
  31. <validationErrorMode>FAIL</validationErrorMode>
  32. </configuration>
  33. </plugin>

上面的插件配置包含了几方面的配置信息:

  • 声明插件
  • 声明数据库驱动的依赖包
  • Flyway 配置——数据库连接配置
  • Flyway 配置——Flyway 参数与行为配置

执行Maven 命令进行Flyway 操作(下面列出几种常用的操作)

  • mvn flyway:init (初始化Flyway metadata )
  • mvn flyway:migrate (执行Flyway 升级操作)
  • mvn flyway:validate (校验Flyway 数据正确性)

4.2.3.  在应用启动时自动运行(结合Spring )

定义在应用启动时自动运行Flyway 的Java 类,并实现其逻辑代码

Java代码

  1. public class FlywayMigration {
  2. private DataSource dataSource;
  3. public void setDataSource(DataSource dataSource) {
  4. this.dataSource = dataSource;
  5. }
  6. public void migrate() {
  7. Flyway flyway = new Flyway();
  8. flyway.setDataSource(dataSource);
  9. flyway.setSchemas("flywaydemo"); // 设置接受flyway进行版本管理的多个数据库
  10. flyway.setTable("schema_version"); // 设置存放flyway metadata数据的表名
  11. flyway.setLocations("flyway/migrations", "com.kedacom.flywaydemo.migrations"); // 设置flyway扫描sql升级脚本、java升级脚本的目录路径或包路径
  12. flyway.setEncoding("UTF-8"); // 设置sql脚本文件的编码
  13. flyway.setValidationMode(ValidationMode.ALL); // 设置执行migrate操作之前的validation行为
  14. flyway.setValidationErrorMode(ValidationErrorMode.FAIL); // 设置当validation失败时的系统行为
  15. flyway.migrate();
  16. }
  17. }

在Spring 中根据上面实现的类来定义(实例化)一个bean

Xml代码

  1. <bean id="flywayMigration" class="com.kedacom.flywaydemo.FlywayMigration" init-method="migrate">
  2. <property name="dataSource" ref="dataSource" />
  3. </bean>

从上面的bean 定义中我们可以看到,我们为flywayMigration 这个bean 实例注入了一个数据源,Flyway 的所有操作将针对这个数据源进行;同时我们通过init-method 属性指定了Spring 在实例化该bean 以后,主动执行该bean的migrate 方法,而该方法内会执行Flyway 更新数据库的操作。

至此,我们达到了在应用启动时,Spring 实例化上下文的时候,在Spring 实例化flywayMigration 这个bean 的时候,自动执行Flyway 更新数据库的操作。

但是,我们还没有达到目的,万一Flyway 还在更新数据库,没有完成更新操作之前,应用程序的其他逻辑已经开始使用数据库进行其他操作了,会导致应用程序产生很多bug ,甚至根本运行不起来。

要解决这个问题,我们可以利用Spring 的bean 依赖原理,让关键的数据库操作bean 依赖于flywayMigration 这个bean ,达到在flywayMigration 没有实例化完成(数据库更新操作完成)之前,不能进行任何其他数据库相关操作。

利用Spring 的bean 依赖让flywayMigration 优先处理数据库更新操作

Xml代码

  1. <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" depends-on="flywayMigration">
  2. <property name="dataSource" ref="dataSource" />
  3. </bean>
  4. <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" depends-on="flywayMigration">
  5. <property name="dataSource" ref="dataSource" />
  6. </bean>

5.  总结

本篇我们介绍了什么是Flyway ,为什么使用Flyway ,以及如何使用Flyway ,但实际产品/ 项目中的情况可能更复杂,仅靠对Flyway 技术使用上的了解并不能达到我们满意的解决方案,为此我将在下一篇中介绍我们结合项目实际的问题形成的一些基于Flyway 的数据库版本管理解决方案。下一篇的内容主要包括:

  • 我们的项目中实际是如何使用 Flyway 的
  • 如何在已有的项目中集成 Flyway
  • 如何在多应用、跨平台、跨语言的环境中使用 Flyway
时间: 2024-11-11 14:13:14

Flyway的第一次认识的相关文章

Flyway数据库版本控制

前言:最近工作上遇到个问题,项目开发过程中,开发代码可以通过svn来版本控制,但数据库又该如何来管理呢?多个人接触数据库,当对表.字段或数据修改后,又怎么来同步呢?经过苦寻,发现了个叫flyway的开源项目:http://flywaydb.org/,java编写,官方的介绍就是我的初衷,岂能不心动? 官网是英文的,查了下居然没有中文文档,难道没有中国人用? 慢慢看了下官方文档,试着做了下,一次成功!(离开电脑,蹦达几下,继续坐回电脑) 自己写个小教程吧 1.将flyway-core-2.3.ja

Flyway客户端使用

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

Flyway 学习时遇到的错误

错误一: No plugin found for prefix 'flyway' in the current project and in the plugin groups  找不到Flyway插件 解决方法: 在项目的根目录去运行Flyway命令.例如此项目放在E:\workspaceidea\monitor中,则需要在此目录下执行命令. 错误二:没有用来记录执行日志的历史表 解决方法: a. 在pom.xml配置文件中加入,这个参数一般是在数据库第一次运行Flyway的时候加上,用来初始

C++第一次的作业感想

1.本周小结:这周第一次开始接触C++,上手之后发现并没有想象中的困难,从一开始模仿到看解释,慢慢了解几个代码的意义,就开始做程序,一个个错误的排查,打的数量多了错误就渐渐少了,也尝试了学长教的if,else的语句,感受到了一点成就感. 遇到的问题和解决:一按运行就跳出,询问了老师之后懂了system("pause"):上网查了才知道还要在开头加一个#include<stdlib.h>. 还有没有找到错误,但就是无法运行.查了书,问了同学也没什么头绪. 下周计划:进一步学习

记第一次用Linux搭建LAMP环境

本文为日记,并非技术博客. 嗯,没错,我决定学习linux系统了.虽然不是第一次接触命令行,不过还是挺有压力的.看了两天的Linux基础视频就开始动手搭建自己的LAMP环境. 关于为什么开始接触Linux呢,主要是最近一直在学前端的知识,想换换口味....以前自己写的小网站也都是用windows下的IIS发布的,所以心血来潮决定试试搭建一个Linux的WEB服务器.既然搭建的是WEB服务器,那么首选自然是LAMP环境,也就是Linux+apache+mysql+php啦.至于为什么是LAMP,当

第一次接触终极事务处理——Hekaton

在这篇文章里,我想给出如何与终极事务处理(Extreme Transaction Processing (XTP) )的第一步接触,即大家熟知的Hakaton.如果你想对XTP有个很好的概况认识,我推荐Kalen Delaney写的关于它的白皮书,另外微软研究院也发布了题为“对于内存数据库的高性能并发控制机制(High-Performance Concurrency Control Mechanisms for Main-Memory Databases)”的研究白皮书,点此下载. 所有XTP维

在CentOS上部署Asp.Net MVC3的第一次尝试

关注mono已经很久了,现在才有时间真正的尝试一下在linux中部署asp.net的网站,也算是记录 一下自己的第一次尝试吧. 我的实践的环境是win7 + VM10 + CentOS6.5 下面就是具体的步骤: 1.在linux下搭建asp.net所需要的环境(mono 3.12.0+jexus 5.6.3.12),这一步也已经有很多 可以参考的文章了,大家可以看看惊鸿哥的博客和张善友先生的博客来搭建环境,我搭建的最终如 下: 2.环境搭建好了,当然就是要开发了.开发我是在VS上,将发布后的文

我的“第一次”,就这样没了:DDD(领域驱动设计)理论结合实践

写在前面 插一句:本人超爱落网-<平凡的世界>这一期,分享给大家. 阅读目录: 关于DDD 前期分析 框架搭建 代码实现 开源-发布 后记 第一次听你,清风吹送,田野短笛:第一次看你,半弯新湖,鱼跃翠堤:第一次念你,燕飞巢冷,释怀记忆:第一次梦你,云翔海岛,轮渡迤逦:第一次认你,怨江别续,草桥知己:第一次怕你,命悬一线,遗憾禁忌:第一次悟你,千年菩提,生死一起. 人生有很多的第一次:小时候第一次牙牙学语.第一次学蹒跚学步...长大后第一次上课.第一次逃课.第一次骑自行车.第一次懂事.第一次和喜

第一次作业:阅读优秀博文感想

我是一只咸鱼 不想承认 也不能否认不要同情我笨 又夸我天真 还梦想着翻身咸鱼就算翻身 还是只咸鱼 输得也诚恳至少到最后 我还有咸鱼 不腐烂的自尊我没有任何天分 我却有梦的天真我是傻 不是蠢我将会证明 用我的一生我 如果有梦有没有错 错过才会更加明白明白坚持是什么我 如果有梦梦要够疯 够疯才能变成英雄 ---<咸鱼>五月天 1.选择 选择计算机这个专业纯属偶然,并非出于对这个专业的热爱或者向往.在没有接触到这个专业之前对计算机的理解仅限于平日里接触到的电脑.从小学二年级第一次接触到第一部台式电脑