Liquibase 简单教程
Liquibase
是一个用于跟踪、管理和应用数据库变化的开源的数据库重构工具。它将所有数据库的变化(包括结构和数据)都保存在 changelog
文件中,便于版本控制,它的目标是提供一种数据库类型无关的解决方案,通过执行 schema 类型的文件来达到迁移。
在项目中启用Liquibase后,数据库会生成两张表:
- databasechangelog —— changelog执行的日志,这张表控制每一个changeset只会执行一次
- databasechangeloglock —— 锁
Spring Boot 集成
添加依赖
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
</dependency>
配置文件
# 启用liquibase
liquibase.enabled=true
# 存储变化的文件(changelog)位置
liquibase.change-log=classpath:/db/changelog/db.changelog-master.xml
# 检查存储变化的文件是否存在
liquibase.check-change-log-location=true
# 分环境执行,若在 changelog 文件中设置了对应 context 属性,则只会执行与 dev 对应值的 changeset
liquibase.contexts=dev
# 执行前首先删除数据库,默认 false。若设置为 true,则执行变更前,会先删除目标数据库,请谨慎
liquibase.dropFirst=false
# 执行更新时将回滚 SQL 写入的文件路径
liquibase.rollback-file=
# 如果spring已配置datasource 数据源,则以下三个数据库连接参数可不配置
## 访问数据库的连接地址
liquibase.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&failOverReadOnly=false&rewriteBatchedStatements=true&useSsl=false
# 访问数据库的用户名
liquibase.user=test
# 访问数据库的密码
liquibase.password=test
如果是简单的使用,只需要下面两条即可
spring.liquibase.enabled=true
spring.liquibase.change-log=classpath:/db/changelog/db.changelog-master.xml
XML 格式使用
格式规范
首先是最外层的标签
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd
http://www.liquibase.org/xml/ns/pro
http://www.liquibase.org/xml/ns/pro/liquibase-pro-4.1.xsd">
</databaseChangeLog>
数据分离
在配置文件中指定的主 changelog 文件中,可以使用 includeAll
标签来引入其他的 changelog
<includeAll path="classpath:/db/changelog/"
filter="cn.cimoc.test.liquibase.MyIncludeAllFilter"
resourceComparator="cn.cimoc.test.liquibase.MyComparator"
/>
参数 | 含义 |
---|---|
path | 扫描的changelog目录 |
filter | 扫描时的过滤器 |
resourceComparator | 执行时的比较器,用来决定多个changelog的执行顺序 |
过滤器
public class MyIncludeAllFilter implements IncludeAllFilter {
@Override
public boolean include(String changeLogPath) {
// 扫描所有以.xml结尾的文件,并排除master和test
return StringUtils.endsWith(changeLogPath, ".xml") && !StringUtils.endsWith(changeLogPath, "-master.xml") && !StringUtils.endsWith(changeLogPath, "-test.xml");
}
}
比较器
public class MyComparator implements Comparator<String> {
/*
* 自定义xml优先级列表
*/
private static final String[] CHANGELOG_FILES_ORDER = new String[]{
"db.changelog-table.xml",
"db.changelog-data.xml"
};
/**
* @params s1 文件1的路径,例如我的例子中就是"/db/changelog/db.changelog-*.xml"
* @params s2 文件2的路径
* @return 负数代表s1优先级高,0代表优先级相同,正数代表s2优先级高
*/
@Override
public int compare(String s1, String s2) {
return getIndex(s1) - getIndex(s2);
}
/**
* 返回路径在上面的优先级列表中的下标
*/
private int getIndex(String s) {
for (int i = 0; i < CHANGELOG_FILES_ORDER.length; i++) {
if (s.contains(CHANGELOG_FILES_ORDER[i])) {
return i + 1;
}
}
return -1;
}
}
changelog-master
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd
http://www.liquibase.org/xml/ns/pro
http://www.liquibase.org/xml/ns/pro/liquibase-pro-4.1.xsd">
<includeAll path="classpath:/db/changelog/"
filter="cn.cimoc.test.liquibase.MyIncludeAllFilter"
resourceComparator="cn.cimoc.test.liquibase.MyComparator"
/>
</databaseChangeLog>
changelog-table
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd
http://www.liquibase.org/xml/ns/pro
http://www.liquibase.org/xml/ns/pro/liquibase-pro-4.1.xsd">
<changeSet id="1" author="lgz">
<createTable tableName="user_info">
<column name="id" type="int" autoIncrement="true">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="age" type="int" defaultValue="" remarks="年龄"/>
<column name="name" type="varchar(20)" defaultValue="" remarks="姓名"/>
</createTable>
</changeSet>
<changeSet id="2" author="lgz">
<createTable tableName="user_account">
<column name="id" type="int" autoIncrement="true">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="username" type="varchar(255)">
<constraints nullable="false"/>
</column>
<column name="password" type="char(32)">
<constraints nullable="false"/>
</column>
</createTable>
</changeSet>
<changeSet id="3" author="lgz">
<addColumn tableName="user_account">
<column name="user_id" type="int">
<constraints nullable="false"/>
</column>
</addColumn>
</changeSet>
</databaseChangeLog>
changelog-data
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd
http://www.liquibase.org/xml/ns/pro
http://www.liquibase.org/xml/ns/pro/liquibase-pro-4.1.xsd">
<changeSet id="1" author="lgz">
<insert tableName="user_info">
<column name="name" value="lgz"/>
<column name="age" value="20"/>
</insert>
</changeSet>
<changeSet id="2" author="lgz">
<insert tableName="user_account">
<column name="username" value="1104738025"/>
<column name="password" value="123456"/>
</insert>
</changeSet>
<changeSet id="3" author="lgz">
<update tableName="user_account">
<column name="user_id" value="1"/>
<where>username = '1104738025'</where>
</update>
</changeSet>
</databaseChangeLog>