数据库版本管理工具之flyway

1.引言  

       随着项目不断的增大,尤其是一个在不断开发完善的项目,随着需求变化,数据库的schema也会跟着变化,数据库也需要不断的扩充,加表加字段,(每一次的增加称作一次DB的迁移migration)你是否还在用着最原始的方式, 用文件管理每次的SQL升级脚本,加了哪些字段,加了那些表,现在可以用数据库版本控制工具轻而易举搞定了。

       flyway支持java API的操作方式,可以和spring 框架进行无缝连接,使其在系统启动的时候检查并升级数据库的版本(特别适合于java项目)。

2.flyway的特点

2.1使用它之前先要了解一些概念:

  • 版本:对数据库的每一次变更可称为一个版本。

  • 迁移:Flyway把数据库结构从一个版本更新到另一个版本叫做迁移。

  • 可用的迁移:Flyway的文件系统识别出来的迁移版本。

  • 已经应用的迁移:Flyway已经对数据库执行过的迁移。

2.2 .flyway最基本的几个命令。

  • Migrate:应用所有的迁移到最新版本,它会在你的DB中新建个表schema_version来存放每次升级的版本信息。

  • Clean:clean all objects

  • Info:打印所有的迁移的信息以及状态。

  • Validate:迁移之前进行验证。

  • Baseline:初始化schema_version表,并插入一条原始verion=1。

  • Repair:它主要做了两件事,移除所有失败的迁移(升级),重置校验和。

2.3.既支持sql方式升级也支持java方式升级

      1)支持SQL(还有PL/SQL,T-SQL)文件的方式进行升级(这就是最原始的方式,但是得按照一定的规则规则,例如:V2_0_0_0__update.sql,  V2_0_0_1__update.sql。

sql脚本的命名规则:

  • prefix: default: V (大写哦) 

  • version: 版本号,也可以使用大小版本组合的方式,小版本号用单 _区分  

  • separator: 分隔符,双下划线 __  

  • description: 描述(你懂得,必须要有意义)  

  • suffix: 后缀 default:  .sql

      2)当然也支持Java方式,继承 JdbcMigration即可,例如我定义了一个升级的类:public class V1_2__Another_user implements JdbcMigration {} 如果你使用JVM平台,建议你用Java API,也支持Android哦。

2.4 可以使用命令行客户端Command-line client来执行命令来升级数据库的版本。

   这儿就不详细介绍了。这个不是重点。重点在介绍java的使用

2.5  当然flyway也提供了插件支持.

        有如下插件支持:Maven, Gradle,SBT和Ant,还有更多Plugins,提供对Spring Boot, Dropwizard, Grails, Play, Griffon, Grunt, Ninja 的支持。 其中可以研究下flyway-test-extensions,有Usage flyway dbunit test、Usage-flyway-spring-test 功能很强大。

3. 在maven项目里面的spring mvc里面使用flyway在系统启动的时候去检查并升级数据库的版本。

3.1引入flyway的jar包,在pom.xml里面内容如下:

<properties>
    <flyway.version>2.3</flyway.version>
</properties>

<!--flyway要用到的jar包  -->
<dependency>
    <groupId>com.googlecode.flyway</groupId>
    <artifactId>flyway-core</artifactId>
    <version>${flyway.version}</version>
    <exclusions>
        <exclusion>
            <artifactId>commons-logging</artifactId>
            <groupId>commons-logging</groupId>
        </exclusion>
    </exclusions>
</dependency>

3.2编写数据库的版本的脚本文件,放到/src/main/resources的flyway里面:

(flyway找脚本的时候默认去/src/mian/resources下面的db/migration,如果要放在别的位置,后面的地方要配置一下

数据库版本管理工具之flyway_第1张图片

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

public class DatabaseFlywayMigration {
 private DataSource dataSource;  
  
    public void setDataSource(DataSource dataSource) {  
        this.dataSource = dataSource;  
    }  
    
    public void migrate() {  
        Flyway flyway = new Flyway();  
        flyway.setDataSource(dataSource);
        flyway.setLocations("flyway"); // 设置flyway扫描sql升级脚本、java升级脚本的目录路径或包路径(表示是src/main/resources/flyway下面,前缀默认为src/main/resources,因为这个路径默认在classpath下面)
        flyway.setEncoding("UTF-8");   // 设置sql脚本文件的编码
        flyway.setOutOfOrder(true);
        //flyway.setDataSource(dataSource);  
  
        //flyway.setSchemas("flywaydemo"); // 设置接受flyway进行版本管理的多个数据库  
        // flyway.setTable("schema_version"); // 设置存放flyway metadata数据的表名  
        //flyway.setValidationMode(ValidationMode.ALL); // 设置执行migrate操作之前的validation行为  
        //flyway.setValidationErrorMode(ValidationErrorMode.FAIL); // 设置当validation失败时的系统行为  
          
        // 设置当validation失败时的系统行为
	try {
	    flyway.setInitOnMigrate(true);
	    flyway.migrate();
	 } catch (FlywayException e) {
	    flyway.repair();
	    e.printStackTrace();
	 }
    }  
}

3.4 设置在系统启动是自动运行DatabaseFlywayMigration类的migrate方法

在ApplicationContext.xml(spring mvc的上下文中加入如下:)

<!-- flayway -->
<bean id="flywayMigration1" class="com.kedacom.flyway.DatabaseFlywayMigration" init-method="migrate">
    <property name="dataSource" ref="dataSource" />
</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 优先处理数据库更新操作:

<!-- 将连接池注入到 JdbcTemplate对象 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" depends-on="flywayMigration1">
    <property name="dataSource" ref="dataSource"></property>
</bean>

至此,运行就可以了。

但是值得注意的是:

 在启动的tomcat的时候,内容如下:

数据库版本管理工具之flyway_第2张图片

但是在schema_version里面已经执行过的版本号如下:

其实并没有执行我的v1_0_0_0__update.sql这个脚本,

DROP TABLE if EXISTS env;
-- 环境 方案 
CREATE TABLE env(
    id varchar(36) not null,
    env_name varchar(50) not null,
    env_username varchar(30) comment '环境用户名',
    env_password varchar(30) comment '环境用户密码',
    ssh_port int default 22,
    state varchar(30) ,
    primary key(id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;

因为没有创建这个数据库表

数据库版本管理工具之flyway_第3张图片

反而是第二个版本的sql脚本给执行了  v1_0_0_1__update.sql

原因是schema_version表的version为1其实被flyway默认为v1_0_0_0版本了,所以没有执行,而version版本为表示初始化schema_version。所以我们可以改为从v2_0_0_0__update.sql开始第一个sql版本。这样就会执行了,反正flyway2.3版本是这样的,不知道后面的版本有没有改善这个问题。

你可能感兴趣的:(数据库版本管理工具之flyway)