Liquibase是开源的数据库表结构管理解决方案,可以轻管理表结构的变更。
众所周知,使用git管理代码可以使得多人协作、版本管理等工作变得异常轻松。但数据库表结构的管理却一直没有很好的解决方案,比如每次变更数据库都要手动执行SQL脚本,不同版本的程序和不同版本的数据库表结构要小心的匹配,跨数据库平台的还需为不同数据库准备不同SQL脚本,数据库表结构只能升级、不能降级。
参考资料:
Liquibase支持大部分数据库(如果不是所有的话),包括:mysql, postgresql, mariadb, mssql, oracle, db2, sybase, h2, derby, firebird, hsqldb, sqlite。
参考资料:
Liquibase使用一种通用的语言描述数据库的变更,代替传统的SQL语句,以实现上述目标。
Liquibase允许使用SQL、XML、JSON、YAML文件格式。SpringBoot默认使用YAML文件格式,这里以YAML格式为例进行说明。
如要为person表增加country列,通常SQL代码为:ALTER TABLE person ADD country varchar(2)
,在Liquibase中则描述为:
- changeSet:
id: 4
author: your.name
changes:
- addColumn:
tableName: person
columns:
- column:
name: country
type: varchar(2)
其中id
是该changeSet的唯一标识,author
则标记该changeSet是谁编写的。
Liquibase可以根据此描述,为不同数据库生成不同SQL代码。并且会在数据库中自动创建DATABASECHANGELOG
表,用于记录哪些changeSet
是执行过的。
由此可知Liquibase的原理还是很简单的。
参考资料:
只要是SQL支持的Liquibase绝大部分都支持。如createTable, addColumn, dropTable, dropColumn, renameColumn, modifyDataType, createIndex, addForeignKeyConstraint 等等。
以下是createTable(创建表)的语句:
changeSet:
id: createTable-example
author: liquibase-docs
changes:
- createTable:
columns:
- column:
name: address
type: varchar(255)
tableName: person
详细语句请参考官方文档:Liquibase Change Types
SpringBoot自带了对Liquibase的支持,使用起来非常方便。只需要在pom.xml
中增加如下配置:
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
</dependency>
默认的yaml文件位于src/main/resources/
db/changelog/db.changelog-master.yaml
,可以直接在这个文件上写入Liquibase代码。
但最佳实践是将不同版本的changelog放在独立的文件。例如1.0
版本的changelog为db.changelog-1.0.yaml
,2.0
版本的chagelog为db.changelog-2.0.yaml
。在db.changelog-master.yaml
将其包含进来。
databaseChangeLog:
- include:
file: db.changelog-1.0.yaml
relativeToChangelogFile: true
- include:
file: db.changelog-2.0.yaml
relativeToChangelogFile: true
完成SpringBoot的配置之后,程序启动时就会解析db.changelog-master.yaml
文件的内容,并和Liquibase自动创建的DATABASECHANGELOG
表的内容进行比对,没有执行的changelog会根据当前数据库类型生成相应的SQL自动执行,并写入DATABASECHANGELOG
。
需要注意的是,Liquibase并不会对表结构自动回滚。比如git从2.0版本切换到1.0版本,数据库结构不会自动回滚到1.0版本。因为数据库结构回滚可能会删表(表里的数据也就没了),是风险极大的操作。Liquebase支持数据库结构回滚,给不同版本的数据库结构做tag
标记,可回滚到某个标记处。对于某些Liquibase无法自动生成回滚语句的(比如insert、update语句),需要自己在changelog编写回滚语句。这些是高级用法,且用的极少,这里就不多做介绍。
在UJCMS项目中就使用了Liquibase作为数据库版本管理工具,可参考实例代码:UJCMS db.changelog-master.yaml
参考资料:
Liquibase对字段默认值的处理非常值得注意,使用defaultValue
的内容一律作为字符串处理,如果希望使用其它数据类型,应使用相应的属性。
YYYY-MM-DD
,hh:mm:ss
orYYYY-MM-DDThh:mm:ss
current_timestamp
current_datetime
或者 current_timestamp(3)
可自动转化为相应数据库的日期函数,如MySQL的now()
now(3)
参考资料:
proerty可以支持数据库类型判断,如:
<property name="now" value="sysdate" dbms="oracle"/>
<property name="now" value="now()" dbms="mysql"/>
<property name="now" value="now()" dbms="postgresql"/>
<column name="join_date" defaultValueComputed="${now}"/>