浅谈Liquibase

Liquibase作为一款开源的数据库架构变更管理工具,可以帮助开发者方便跟踪、管理数据库变化的修订。其支持MySQL、PostgreSQL、Oracle等众多数据库

浅谈Liquibase

abstract.png

集成Spring

Spring boot内置了对Liquibase的支持,只需要在项目中引入Liquibase依赖并进行配置即可

<!--Liquibase-->
<dependency>
    <groupId>org.liquibase</groupId>
    <artifactId>liquibase-core</artifactId>
    <version>3.6.3</version>
</dependency>

对于配置而言,Liquibase默认会使用Spring配置项的数据库连接。如果期望不使用该默认配置,也可以显式单独配置

# 数据库配置
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/db1?useSSL=false
spring.datasource.username=root
spring.datasource.password=123456

# 使能 Liquibase
spring.liquibase.enabled=true
# 指定 Liquibase 变更记录的位置
spring.liquibase.change-log=classpath:/db/changelog/master.xml

在上面的配置项spring.liquibase.change-log中我们指定了Liquibase 变更记录的位置。事实上,通常这只是一个master配置文件,如下所示。其中通过include标签来包含、汇聚所有的changlog文件

<?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"
        xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
            http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.9.xsd"
>


    <!-- master.xml文件的作用就是汇集所有changlog文件 -->
    <!-- relativeToChangelogFile 为 true 时表示使用的是相对路径 而不是classpath-->
    <include file="changelog-1.0.xml" relativeToChangelogFile="true"/>

</databaseChangeLog>

目录结构如下所示

浅谈Liquibase

figure 1.jpeg

详解ChangeLog

一个典型地changlog文件如下所示,其记录了我们对数据库的变更、修订内容。这里我们使用XML进行介绍,其实Liquibase支持SQL、XML、JSON、YAML等多种形式

<?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"
        xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
            http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.9.xsd"
>


    <changeSet id="create_density_range" author="Aaron" runOnChange="true">
        <!-- 执行该SQL的先决条件: 该表不存在 -->
        <preConditions onError="MARK_RAN" onFail="MARK_RAN">
            <not>
                <tableExists tableName="density_range"/>
            </not>
        </preConditions>

        <createTable remarks="密度区间" tableName="density_range">
            <column name="id" type="INTEGER" remarks="主键id" autoIncrement="true" startWith="1" incrementBy="1">
                <constraints primaryKey="true" nullable="false"/>
            </column>
            <column name="low_start" remarks="低密度区间: 下限" type="INTEGER"/>
            <column name="low_end" remarks="低密度区间: 上限" type="INTEGER"/>
            <column name="medium_start" remarks="中密度区间: 下限" type="INTEGER"/>
            <column name="medium_end" remarks="中密度区间: 上限" type="INTEGER"/>
            <column name="high_start" remarks="高密度区间: 下限" type="INTEGER"/>
            <column name="high_end" remarks="高密度区间: 上限" type="INTEGER"/>
        </createTable>
    </changeSet>

    <changeSet id="create_geohash_6" author="Aaron" runOnChange="true">
        <preConditions onError="MARK_RAN" onFail="MARK_RAN">
            <not>
                <tableExists tableName="geohash_6"/>
            </not>
        </preConditions>

        <createTable remarks="GeoHash6信息" tableName="geohash_6">
            <column name="id" type="INTEGER" remarks="主键id" autoIncrement="true" startWith="1" incrementBy="1">
                <constraints primaryKey="true" nullable="false"/>
            </column>
            <column name="geohash" remarks="GeoHash6数据" type="VARCHAR(255)"/>
            <column name="center_lng" remarks="中心点经度" type="VARCHAR(255)"/>
            <column name="center_lat" remarks="中心点纬度" type="VARCHAR(255)"/>
            <column name="max_lng" remarks="最大经度" type="VARCHAR(255)"/>
            <column name="max_lat" remarks="最大纬度" type="VARCHAR(255)"/>
            <column name="min_lng" remarks="最小经度" type="VARCHAR(255)"/>
            <column name="min_lat" remarks="最小纬度" type="VARCHAR(255)"/>
            <column name="is_hz_edge" remarks="是否为边界" type="BOOLEAN"/>
        </createTable>
    </changeSet>

    <changeSet id="add tag" author="Aaron">
        <!-- tag 为版本号 -->
        <tagDatabase tag="1.0"/>
    </changeSet>

</databaseChangeLog>
  • 「changeSet标签」:出于便于阅读的角度考虑,每个changeSet每次只包含对一张表的修订操作。同时,对于已执行过changeSet一般情况下不应做任何修改
  • 「runOnChange属性」:用于控制每次运行changeSet时,如果本次changeSet发生修改是否重新执行。其默认值为false,当本次changeSet发生修改不会执行变更,而是会发出错误以提醒发生了意外修改。其原理是通过比对changeSet的MD5校验和、存储在DATABASECHANGELOG表中的MD5SUM进行 判定的。典型地对于存储过程场景而言,该属性一般设置为true。这样每次对历史changeSet进行修改后,都需要Liquibase重新执行该changeSet以保证修改生效
  • 「preConditions标签」:控制数据库变更的先决条件。如果先决条件满足要求,则会执行该标签后相应的数据库变更;如果先决条件在执行过程抛出异常,则行为由「onError属性」控制;如果先决条件不满足要求,则行为由「onFail属性」控制;
  • 「onFail、onError属性」:preConditions标签的onFail、onError属性可用的取值有:
    • 「CONTINUE」:跳过该changeSet、会在下次更新时再次尝试。继续执行changeLog
    • 「HALT」:停止执行整个changeLog。这也是默认值
    • 「MARK_RAN」:跳过该changeSet同时将其标记为已执行。继续执行changeLog
    • 「WARN」:发出警告并继续执行changeSet、changeLog
  • 「tagDatabase」:对本次版本的数据库修订打标签

至此当我们启动SpringBoot项目后,即可发现数据库不仅包含了我们期望的业务表,还新增了两张Liquibase相关的表——DATABASECHANGELOG、DATABASECHANGELOGLOCK

浅谈Liquibase

figure 2.jpeg

而对于DATABASECHANGELOGLOCK锁表而言,如果某记录的LOCKED字段为1,则表示该锁被占有了。故在Liquibase锁无法正常释放时,可能会导致无法创建表,这时可通过手动置零来释放锁

生成ChangeLog

liquibase-maven-plugin可以帮助我们直接地从数据库中创建、生成相应的ChangeLog文件,配置如下

<build>
    <plugins>
        <plugin>
            <groupId>org.liquibase</groupId>
            <artifactId>liquibase-maven-plugin</artifactId>
            <version>3.6.3</version>
            <configuration>
                <!--生成Changelog的输出目录-->
                <outputChangeLogFile>${basedir}/src/main/resources/db/generate/changeLog.xml</outputChangeLogFile>
                <!--DB连接信息-->
                <driver>com.mysql.jdbc.Driver</driver>
                <url>jdbc:mysql://localhost:3306/db1?useSSL=false</url>
                <username>root</username>
                <password>123456</password>
                <dropFirst>false</dropFirst>
                <verbose>true</verbose>
                <logging>debug</logging>
                <promptOnNonLocalDatabase>false</promptOnNonLocalDatabase>
                <outputFileEncoding>UTF-8</outputFileEncoding>
                <propertyFileWillOverride>true</propertyFileWillOverride>
             </configuration>
        </plugin>
    </plugins>
</build>

操作、效果如下所示

浅谈Liquibase

figure 3.jpeg

原文始发于微信公众号(青灯抽丝):浅谈Liquibase

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/156501.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!