数据库开发升级变更技术探究
【Liquibase】
Liquibase是一个独立于数据库的开源库,用于跟踪、管理和部署数据库设计的变化。它发布于2006年,旨在更容易跟踪数据库的变化,特别适合在敏捷软件开发环境中使用。
概述
对数据库的所有更改都存储在文本文件(XML、YAML、JSON或SQL)中,并通过 "id "和 "author "标签以及文件本身的名称来识别。在每个数据库中都存储了一个含有所有部署的更改列表,在数据库更新时都会被查阅,以确定需要部署哪些新的更改。 有一个特点要注意,这种方法不是用版本号来管理数据库设计变化,因此没有数据库的版本号,但这种方法允许多个开发人员和多个代码分支的协同工作。
Liquibase在第一次执行changeLog文件时,会自动创建DatabaseChangeLog表和DatabaseChangeLogLock表。
主要功能
l 30多个内置数据库重构器
l 可扩展性,创建自定义更改
l 将数据库更新为当前版本
l 回滚到数据库中的最后X次修改
l 回滚数据库更改到特定日期/时间
l 回滚数据库到 "标签"
l 可以保存数据库更新和回滚的SQL,以便手动查看。
l 独立的IDE和Eclipse插件
l 用于包括/排除要执行的更改集的上下文
l 数据库差异报告
l 数据库差异变化记录的生成
l 能够创建变更日志进而生成现有数据库的能力。
l 数据库变更文档的生成
l DBMS检查、用户检查和SQL检查的前提条件
l 能够将变更日志分割成多个文件,便于管理。
l 可通过命令行、Apache Ant、Apache Maven、servlet容器或Spring框架执行。
l 支持10个数据库系统
商业版
Datical既是Liquibase项目的最大贡献者,也是Datical DB的开发者,Datical DB是一个提供Liquibase核心功能和附加功能的商业产品。
l 变更预测。预测即将执行的变化,在运行之前就预测即将执行的变化,以确定这些变化将如何影响你的数据。
l 规则引擎来执行企业标准和策略。
l 支持数据库的存储逻辑:函数、存储过程、包、表空间、触发器、序列、用户定义的类型、同义词等。
l 比较数据库,可以对两个数据库设计定义进行比较,以识别变更,并轻松地将其移动到变更日志中。
l 变更集向导,以数据库中立的方式轻松定义和捕获数据库变更。
l 部署计划向导,用于建模和管理您的逻辑部署工作流程。
l Jenkins、Bamboo、UrbanCode、CA Release Automation (Nolio)、Serena Release Automation、BMC Bladelogic、Puppet、Chef、以及所有流行的源码控制系统如SVN、Git、TFS、CVS等的插件。
使用Datical DB的人员包括DBA、发布经理、DevOps团队、应用程序所有者、架构师以及参与应用程序发布过程的开发人员。它以程序化的方式管理数据库设计变化和部署程序代码,消除了错误和延迟,实现了快速敏捷发布。Datical DB建立在Liquibase数据模型方法的基础上,在应用程序版本从开发到测试到生产环境的过程中,管理数据结构的特定内容。在部署之前,Datical可以在任何环境中预览设计变化的影响,从而降低了风险,使应用程序的变化更加顺畅和快速。
Liquibase开发人员Nathan Voxland是Datical公司的高管。
【使用案例】
添加依赖
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
<version>3.8.7</version>
</dependency>
数据库变更日志文件样本
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd
http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd">
<changeSet author="user1" id="someUniqueId">
<addColumn tableName="user">
<column name="nickName" type="varchar(255)" />
</addColumn>
</changeSet>
</databaseChangeLog>
在上面这个简单例子中,我们在表格user中添加一个新的字段nickeName。
注意变更集合是如何通过一个id和作者来标识的,所以要确保标识唯一,并且只使用一次。
用 "Spring Bean"运行Liquibase
我们在应用程序启动时部署更改的第一个选择是通过Spring bean。当然,还有很多其他的方法,但如果我们要使用Spring框架的话,这是个很好的而且简单的方法。
@Bean
public SpringLiquibase liquibase() {
SpringLiquibase liquibase = new SpringLiquibase();
liquibase.setChangeLog("classpath:liquibase-changeLog.xml");
liquibase.setDataSource(dataSource());
return liquibase;
}
注意: 我们将其指向一个在classpath上存在的有效的changeLog文件。
如果使用的是Spring Boot
如果你使用的是Spring Boot,就不需要为Liquibase定义一个Bean。
你只需要将你的变更日志放到:
"db/changelog/db.changelog-master.yaml "中,Liquibase的更改部署就会在启动时自动运行。
需要注意的是:
l 你需要添加 "liquibase-core "依赖。
l 你可以使用 "liquibase.change-log "属性来更改默认的日志文件,例如:
liquibase.change-log=classpath:liquibase-changeLog.xml
在Spring Boot中禁用Liquibase
有时,我们可能需要在启动时禁用Liquibase迁移的执行。
我们最简单的方法是使用 spring.liquibase.enabled 属性。这样一来,所有剩下的Liquibase配置就不会被触动。
下面是Spring Boot 2的例子:
spring.liquibase.enabled=false
对于 Spring Boot 1.x,我们需要使用 liquibase.enabled 属性。
liquibase.enabled=false
使用Maven插件生成变更记录
我们可以使用Liquibase Maven插件来生成一个变更记录文件,而不是手动编写记录文件,这样可以节省很多工作。
插件配置
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-maven-plugin</artifactId>
<version>3.x.x</version>
</dependency>
<plugins>
<plugin>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-maven-plugin</artifactId>
<version>3.4.1</version>
<configuration>
<propertyFile>src/main/resources/liquibase.properties</propertyFile>
</configuration>
</plugin>
</plugins>
从现有数据库中生成变更记录
我们可以使用该插件从现有的数据库中生成一个变更记录。
mvn liquibase:generateChangeLog
以下是liquibase的属性配置:
url=jdbc:xxxx
username=xxx
password=xxx
driver=x.Driver
outputChangeLogFile=src/main/resources/liquibase-outputChangeLog.xml
最终的结果是一个changeLog文件,我们可以用它来创建一个初始DB设计定义或填充数据。下面是我们的示例的样子:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<databaseChangeLog >
<changeSet author="user1 (generated)" id="unique-1">
<createTable tableName="APP_USER">
<column autoIncrement="true" name="id" type="BIGINT">
<constraints primaryKey="true"/>
</column>
<column name="accessToken" type="VARCHAR(255)"/>
<column name="needCaptcha" type="BIT(1)">
<constraints nullable="false"/>
</column>
<column name="password" type="VARCHAR(255)"/>
<column name="refreshToken" type="VARCHAR(255)"/>
<column name="tokenExpiration" type="datetime"/>
<column name="username" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="preference_id" type="BIGINT"/>
<column name="address" type="VARCHAR(255)"/>
</createTable>
</changeSet>
</databaseChangeLog>
从两个数据库之间的差异生成变化记录
我们可以使用插件从两个现有数据库(例如:开发数据库和生产数据库)之间的差异生成一个变更记录文件。
mvn liquibase:diff
下面是属性配置:
changeLogFile=src/main/resources/liquibase-changeLog.xml
url=jdbc:xxxxxx
username=xxxx
password=xxxx
driver=xxxxx.Driver
referenceUrl=jdbc:xxxxx
diffChangeLogFile=src/main/resources/liquibase-diff-changeLog.xml
referenceDriver=xxxxx
referenceUsername=xxx
referencePassword=xxx
下面是生成的变更记录的片段:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<databaseChangeLog>
<changeSet author="user1" id="unique-id-1">
<dropColumn columnName="nickName" tableName="user"/>
</changeSet>
</databaseChangeLog>
这是一个超级强大的方法来进化你的数据库,例如,允许Hibernate自动生成一个新的设计定义来进行开发,然后用它作为参考点来对照旧的设计定义。
使用Liquibase Hibernate插件
如果应用程序使用Hibernate,我们来看一个非常有用的生成变更记录的方法。
插件配置
首先,让我们把新插件配置好,并使用正确的依赖关系。
<plugins>
<plugin>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-maven-plugin</artifactId>
<version>3.x.x</version>
<configuration>
<propertyFile>src/main/resources/liquibase.properties</propertyFile>
</configuration>
<dependencies>
<dependency>
<groupId>org.liquibase.ext</groupId>
<artifactId>liquibase-hibernate4</artifactId>
<version>3.5</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>X.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>X.RELEASE</version>
</dependency>
</dependencies>
</plugin>
</plugins>
从生产数据库和开发实体数据之间的差异生成变化记录
现在,有趣的部分来了。我们可以使用这个插件从现有正式数据库(例如生产数据库)和我们的开发实体数据的差异中生成一个变更记录文件。
因此,为了使事情变得简单,一旦修改了一个实体,你可以简单地对照旧的DB设计定义生成修改,从而获得一个干净而又强大的方式来进化你在生产数据库中的设计定义。
以下是liquibase的属性:
changeLogFile=classpath:liquibase-changeLog.xml
url=jdbc:xxxxx
username=xxxx
password=xxx
driver=xxxx
referenceUrl=hibernate:xxxx
?dialect=org.hibernate.dialect.MySQLDialect
diffChangeLogFile=src/main/resources/liquibase-diff-changeLog.xml
注意:referenceUrl使用的是包扫描,所以需要方言参数。
【官方网站】
【最新版本】
3.8.7于2020年2月24日
【License】
Apache License 2.0
【Flyway】
Flyway是一个开源的数据库升级迁移工具。
Flyway 基于七个基本命令:迁移、清理、信息、验证、撤销、基线和修复。
迁移可以用SQL(支持特定数据库的语法,如PL/SQL、T-SQL等)或Java(用于高级数据转换或处理LOB)。
它有一个命令行客户端,一个用于在应用程序启动时迁移数据库的Java API(也适用于Android),一个Maven插件和一个Gradle插件。
插件支持包括Spring Boot、Dropwizard、Grails、Play、SBT、Ant、Griffon、Grunt、Ninja等。
支持的数据库包括Oracle、SQL Server、DB2、MySQL(包括Amazon RDS、Aurora MySQL、MariaDB)、Percona XtraDB、PostgreSQL(包括Amazon RDS和Heroku)、Aurora PostgreSQL、CockroachDB、Redshift、Informix、H2、Hsql、Derby、SQLite、SAP HANA、Sybase ASE、Phoenix和Firebird。
业内影响
仅在2018年,Flyway就获得了1150万次下载。
2015年1月,Flyway被列入了Thoughtworks科技雷达的 "推荐使用"板块,
2019年7月,Flyway被Redgate收购。
Flyway是如何工作的
Flyway通过添加一张记账表来记录和跟踪变更是否被部署,何时被部署,由谁部署。这张表还会记录部署校验和,以及是否部署成功。
该框架执行以下步骤以适应不断变化的数据库设计定义:
l 检查一个数据库设计定义,以定位其元数据表(默认情况下是SCHEMA_VERSION)。如果元数据表不存在,它将创建一个
l 扫描应用程序的classpath,以寻找可用的变更。
l 根据元数据表比较变更情况。如果版本号低于或等于标记为当前版本,则会被忽略。
l 将任何剩余的变更标记为待处理的变更。根据版本号进行排序,并按顺序执行。
l 随着每次变更的部署,元数据表也会相应地更新
Flyway 支持以下基本命令来管理数据库迁移:
Info: 打印数据库模式的当前状态/版本。它打印出哪些变更正在等待中,哪些变更已经被部署,应用的变更状态以及何时部署的。
Migrate:将数据库设计定义变更到当前版本。它扫描classpath以寻找可用的变更,并部署待处理的变更。
Baseline:对现有数据库进行基准化,不包括迁移,包括基准线版本。基准线设定以后有助于在现有数据库中实行增量变更,即可以正常部署较新的变更。
Validate: 根据可用的变更来验证当前的数据库模式。
Repair: 修复元数据表。
Clean:丢弃已配置设计定义中的所有对象。所有数据库对象都会被丢弃。因此,不要在任何生产环境数据库中使用clean。
【使用案例】
插件安装配置
<plugin>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-maven-plugin</artifactId>
<version>xxx</version>
</plugin>
这个插件有四种配置方法:
插件配置
<plugin>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-maven-plugin</artifactId>
<version>xxx</version>
<configuration>
<url>XXX</url>
<user>XXX</user>
<password>XXX</password>
<schemas>
<schema>schemaName</schema>
</schemas>
</configuration>
</plugin>
Maven属性
<project>
<properties>
<flyway.url>XXX</flyway.url>
<flyway.user>XXX</flyway.user>
<flyway.password>XXX</flyway.password>
<flyway.schemas>schemaName</flyway.schemas>
</properties>
</project>
外部配置文件
flyway.url=XXX
flyway.user=XXX
flyway.password=XXX
flyway.schemas=schemaName
默认的配置文件名称是flyway.properties,它应该和pom.xml文件位于同一目录下。编码由flyway.encoding指定(默认为UTF-8)。
如果您使用任何其他名称(如 customConfig.properties)作为配置文件,那么在调用 Maven 命令时应该明确指定它。
mvn -Dflyway.configFile=customConfig.properties
系统属性
最后,在命令行中调用Maven时,所有的配置属性也可以指定为系统属性:
mvn -Dflyway.url=databaseUrl -Dflyway.user=databaseUser -Dflyway.password=databasePassword
-Dflyway.schemas=schemaName
以下是当一个配置以多种方式指定时的优先顺序:
1. 系统属性
2. 外部配置文件
3. Maven属性
4. 插件配置
定义第一次迁移
Flyway 遵循以下变更脚本的命名规则:
<Prefix><Version>__<Description>.sql
其中:
l <Prefix> - 默认前缀为V,可以在上述配置文件中使用
l flyway.sqlMigrationPrefix属性配置。
l <Version> - 迁移版本号。主要版本和次要版本可以用下划线分开。迁移版本应该总是以1开头。
l <Description> - 迁移的文本描述。描述需要用双下划线与版本号分开。
比如: V1_1_0__my_first_migration.sql
接下来,让我们在$PROJECT_ROOT中创建一个目录db/migration,用一个名为V1_0__create_employee_schema.sql的变更脚本来创建雇员表,其中包含SQL指令。
CREATE TABLE IF NOT EXISTS `employee` (
`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` varchar(20),
`email` varchar(50),
`date_of_birth` timestamp
)ENGINE=InnoDB DEFAULT CHARSET=UTF8;
执行变更
接下来,我们从$PROJECT_ROOT中调用以下Maven命令来执行数据库变更:
mvn clean flyway:migrate -Dflyway.configFile=myFlywayConfig.properties
第一次成功变更成功以后,数据库设计定义应该是如下的样子:
employee:
+----+------+-------+---------------+
| id | name | email | date_of_birth |
+----+------+-------+---------------+
我们可以重复上述设计定义和执行步骤来做更多的变更。
定义和执行第二次变更
让我们通过创建第二个变更文件,名称为
V2_0_create_department_schema.sql,包含两条语句,来看看第二个迁移是什么样子的。
CREATE TABLE IF NOT EXISTS `department` (
`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` varchar(20)
)ENGINE=InnoDB DEFAULT CHARSET=UTF8;
ALTER TABLE `employee` ADD `dept_id` int AFTER `email`;
我们执行类似的变更命令。而现在,我们的数据库模式发生了变化,为雇员表增加了一个新的列和一个新的部门表。
employee:
+----+------+-------+---------+---------------+
| id | name | email | dept_id | date_of_birth |
+----+------+-------+---------+---------------+
department:
+----+------+
| id | name |
+----+------+
我们现在可以通过调用下面的Maven命令来验证这两个变更是成功的:
mvn flyway:info -Dflyway.configFile=myFlywayConfig.properties
禁用Spring Boot中的Flyway
有时,我们可能需要在某些情况下禁用Flyway变更。
例如,在测试过程中,从实体生成数据库设计定义是一种常见的做法,遇到这种情况,我们可以在测试配置文件下禁用Flyway。
让我们来看看Spring Boot中的做法有多简单。
Spring Boot 1.x
我们需要做的就是在application-test.properties文件中设置
flyway.enabled属性。
flyway.enabled=false
Spring Boot 2.x
在最新版本的Spring Boot中,该属性已被更改为 spring.flyway.enabled。
spring.flyway.enabled=false
清空 FlywayMigrationStrategy
如果我们只想在启动时禁用Flyway自动变更,但仍能手动触发变更,那么使用上述属性并不是一个好的选择。
这是因为在这种情况下,Spring Boot 不会再自动配置 Flyway。因此,我们必须自己提供,这不是很方便。
为了实现这样的需求,我们可以启用Flyway,同时实现一个空的FlywayMigrationStrategy配置类:
@Configuration
public class EmptyMigrationStrategyConfig {
@Bean
public FlywayMigrationStrategy flywayMigrationStrategy() {
return flyway -> {
// do nothing
};
}
}
这样做会在应用程序启动时禁用Flyway迁移,同时我们仍然可以手动触发变更。
@RunWith(SpringRunner.class)
@SpringBootTest
public class ManualFlywayMigrationIntegrationTest {
@Autowired
private Flyway flyway;
@Test
public void skipAutomaticAndTriggerManualFlywayMigration() {
flyway.migrate();
}
}
【官方网站】
【最新版本】
6.4.0于2020年4月21日
【License】
Apache License 2.0
【小结】
本文对于数据库相关的设计定义及其在开发过程中常用的工具做了一番介绍,希望对现有或者以后的业务开发提供帮助和借鉴。
- 点赞
- 收藏
- 关注作者
评论(0)