数据库Scheme的版本控制——DB Migrations


1 概述

当今的大多数软件开发团队已经掌握了使用SVN等SCM工具对源代码和文档进行有效的版本控制,

但是,如何将DB的变更也纳入到版本控制中却是一个亟待解决的难题;

这个问题普遍存在却被严重忽视,常见的最“正规”的做法就是在工程的DB目录下随意堆放sql脚本,在需要的时候从里面挑选出要执行的脚本或脚本片段拿去执行;

这种做法非常的繁琐而容易出错,严重拖累了软件开发团队前进的脚步。

2 MyBatis Schema Migrations介绍

The MyBatis Schema Migrations tool(http://code.google.com/p/mybatis/wiki/Migration 下文简称Migrations)是一个开源的用于DB版本控制的命令行工具,

Migrations通过生成统一格式的DDL脚本模板、在目标DB中记录版本信息和当前状态,使得多人开发团队可以在多个DB环境上井然有序的工作,为敏捷和迭代开发提供强有力的技术保障。

同时Migrations学习和使用又非常简单,常用的命令不到10个;

3 DB的版本控制流程


3.1 安装Migrations命令行工具

首先要为每个项目成员安装Migrations,安装过程很简单:

  • 首先,下载最新版本的压缩包(http://code.google.com/p/mybatis/downloads/list?can=3&q=Product%3DMigrations),然后解压(假设解压到D:\zk-env\migrations310);
  • 打开命令行工具,设置环境参数如下(假设你已安装了JDK):

@echo off
set JAVA_HOME=%cd%\jdk1.7.0_10
set PATH=%JAVA_HOME%\bin;%PATH%
set MIGRATIONS_HOME=%cd%\migrations310
set PATH=%MIGRATIONS_HOME%\bin;%PATH%

migrate
  • 然后就可以开始使用了;

3.2 初始化Migrations工作目录

接下来需要在你的工程下为Migrations创建一个工作目录(如D:\zk-env\workspace\KTF-UAAS\db);

键入下列命令来初始化工作目录:

d:
cd D:\zk-env\workspace\KTF-UAAS\db
migrate init
dir

然后会发现工作目录下增加了drivers、environments、scripts目录,它们分别用来存放DB驱动、各个环境DB连接参数和DB变更脚本;

3.2.1 配置数据库驱动

将项目实际使用的数据库驱动jar拷贝到drivers目录下;

3.2.2 配置数据库连接

打开environments目录,编辑development.properties为Migrations指定开发环境DB的连接参数,修改时区为time_zone=GMT+8:00(假设您的团队在中国大陆);

参照development.properties创建uat.properties、sit.properties等用于指定uat环境和集成测试环境DB连接参数;

3.2.3 记录数据库基线

scripts目录中的bootstrap.sql用于记录数据库的最原始的状态——基线,即你在使用Migrations工具之前的数据库Scheme;

3.2.4 提交Migrations工作目录到SVN

为了在整个团队统一Migrations配置,完成上述配置后需将工作目录提交SVN,然后其他人update即可;

另外,接下来每个开发人员在自己本地创建的DB变更脚本也会放在scripts目录下通过SVN进行版本控制;


接下来,项目组成员就可以各自在本地使用Migrations创建数据库变更了;

3.3 创建数据库变更

键入下列命令创建一个数据库变更:新建表TAbc

migrate new "liyq add table tabc"

然后scripts目录下会增加一个文件——20130709155240_liyq_add_table_tabc.sql,内容如下:

--// liyq add table tabc
-- Migration SQL that makes the change goes here.


--//@UNDO
-- SQL to undo the change goes here.

根据注释不难猜到这是一个模板,分上下两部分:上半部分(也就是–//@UNDO前)是要对数据库做的变更操作脚本,下半部分是与之对应的回退脚本;

这里涉及到一个技巧:

我们不需要手工编写繁琐的DDL,只需在DB管理工具中进行相应的变更操作(例如新建表、增加字段、索引等),然后生成DDL脚本粘贴到上面的模板文件的上半部分;

然后再在DB管理工具中进行反向的变更操作(删除表、字段、索引等),然后生成回滚语句粘贴到20130709155240_liyq_add_table_tabc.sql的下半部分;

这样便完成了DB变更脚本的编写,同时DB状态没有发生变化(使用Migrations工具的一条最重要原则——永远且只通过Migrations命令行执行脚本来改变数据库结构,
因为一旦通过命令行以外方式改变了数据库,脚本就不能完整记录数据库变更,会导致将来脚本执行出错);


3.4 在不同环境执行DB变更

接下来就可以通过Migrations执行上述脚本来改变目标DB,并验证脚本正确性了;

3.4.1 查看目标DB状态

执行前先看看DB的当前状态——哪些脚本已经执行过了,哪些还没执行

migrate status

例如下图表明:当前DB处于版本20130620154141,本地的20130709163435变更还未执行;详见http://mybatis.org/migrations/status.html

数据库Scheme的版本控制——DB Migrations_第1张图片

3.4.2 前进

执行“migrate up”命令,Migrations会在目标DB执行所有还未执行的脚本(这里只有20130709163435)

数据库Scheme的版本控制——DB Migrations_第2张图片

然后再次查看DB状态,发现20130709163435已执行!

数据库Scheme的版本控制——DB Migrations_第3张图片

此时你还会发现目标DB中增加了一个ChangeLog表,没错,Migrations正是通过这个表来记录DB状态的;

3.4.3 后退

执行“migrate down”命令,Migrations会在目标DB“后退一步”——执行当前版本对应的回退脚本,使目标DB回退到上一个版本(20130620154141)的状态,如下图:

数据库Scheme的版本控制——DB Migrations_第4张图片

数据库Scheme的版本控制——DB Migrations_第5张图片

3.4.4 在其它DB环境前进和后退

上面的三个命令(status、up、down)都可以增加一个env参数,用来告诉Migrations在哪个DB执行该命令,

例如migrate status --env=uat用来查看uat.properties中指向的那个目标DB的当前状态

没有指定env参数时,默认为development;

通过这个简单的参数,团队可以轻松的管理多个DB环境状态,任意切换、前进和后退,而脚本只有一套。


至此,我们完成了一个DB变更的开发和测试,并且在多个DB实例中执行了这一变更。

3.5 脚本文件的共享与同步

虽然你已经通过执行上述DB变更改变了DB状态,但团队中的其他成员的工作目录中还没有这个变更脚本,

这似乎是有问题的,至少其它人无法回退这一变更,在你回退后其他人也无法前进到该变更所在的DB版本!

出现这个问题是因为Migrations在目标DB中记录该DB的变更(通过那个ChangeLog表),而对于团队如何分发和同步变更脚本却无法控制,

因此我们需要借助SVN来在团队中共享和同步脚本,这没什么特别的,跟所在工程下的其它目录和文件一样进行SVN操作即可;

不过好在即使是脚本没有同步的情况下执行Migrations命令也不太可能造成冲突,因为Migrations生成的脚本文件是带时间戳的,精确到秒,除非多个人在同一秒内建了同名的变更才可能冲突。

3.6 导出DB变更脚本

3.6.1 系统发布的重要环节——DB发布

随着开发工作的推进项目中的DB变更越来越多。

如果你是这个项目的开发经理,某一天你决定要做一次生成发布,把团队过去一个月的工作成果发布到生产环境供客户使用,

此时,你除了要为应用构建最新版本的war包以外,还要准备一个DB变更脚本用来在生产DB执行,因为过去的一个月中你的团队除了修改了大量代码,还对开发测试环境的DB做了大量变更,

这些变更必须准确无误的在生产DB中也执行一遍,否则新版本的应用将无法工作。

于是你对工程进行SVN更新,进入db/scripts目录,映入你眼帘的是清晰整齐的脚本文件,

轻轻键入一个命令(migrate status --env=xxx)就能清楚的知道各个DB环境的状态;

3.6.2 生成DB变更脚本

你可能会打算直接在DB目录中找出需要发布的脚本文件拿到生产环境去执行,但这样做就跟没有使用Migrations的团队没什么区别了;

Migrations的script命令就是用来做这件事的,执行下列命令,你会得到想要的东西:

migrate script 20130614164456 20130709163435 > release20130710.sql

如果将上面命令中的两个版本号对调位置,得到的就是本次系统发布的DB回退脚本,

一旦你在生产DB执行了数据库变更后又不想发布应用了(比如突然发现这个应用版本存在严重缺陷),

那么这个回退脚本就派上用场了——它能帮你把生产DB恢复到之前的状态——能够使前一版本应用正常工作的状态,而不至于使你陷入进退两难!



你可能感兴趣的:(DB,migrations,开发管理)