优秀的编程知识分享平台

网站首页 > 技术文章 正文

Liquibase+Spring+Maven: 管理数据库轻松搞定

nanyue 2025-01-09 15:09:39 技术文章 4 ℃

Liquibase是一款数据库版本控制工具,它可以帮助开发人员对数据库进行管理和追踪。Liquibase 提供了许多功能,包括数据库变更的版本控制、可重复的和可移植的数据库脚本、数据库迁移、多数据库支持等。使用 Liquibase 可以帮助开发人员更好地管理和维护数据库,提高开发效率和质量

关键组成

Liquibase 支持XML、YAML和JSON格式的脚本来描述数据库变更,这些脚本可以被版本控制系统管理,并且可以根据需要进行合并和冲突解决。同时,Liquibase 还支持多种数据库管理系统,包括 Oracle、MySQL、PostgreSQL、Microsoft SQL Server 等。

下面介绍下liquibase的关键组成。以xml为例,项目配置如下。

master.xml

Liquibase的一个changelog文件,它包含了所有的changelog文件

<?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">

  <property name="now" value="now()" dbms="h2"/>
  <property name="now" value="now()" dbms="mysql, mariadb"/>

  <property name="floatType" value="float4" dbms="postgresql, h2"/>
  <property name="floatType" value="float" dbms="mysql, oracle, mssql, mariadb"/>
  <property name="clobType" value="clob" dbms="h2"/>
  <property name="clobType" value="clob" dbms="mysql, oracle, mssql, mariadb, postgresql"/>
  <property name="uuidType" value="varchar(36)" dbms="h2, mysql, mariadb"/>

  <include file="liquibase/changelog/00000000000000_initial_schema.xml" relativeToChangelogFile="false"/>
</databaseChangeLog>

changelog

Liquibase中的一个重要概念,支持多种格式,主要有XML/JSON/YAML/SQL等。示例中是XML格式00000000000000_initial_schema.xml

changelog用于记录数据库的变更历史,由多个changeset组成,每个changeset代表一个数据库变更。

changeset

一个包含单个数据库变更的单元。每个changeset都有一个唯一的ID和author属性,用于标识该changeset。

示例中我们向数据库新增了一张用户表并初始化一些用户数据

<changeSet id="00000000000001" author="admin">
    <createTable tableName="user">
        <column name="id" type="bigint" autoIncrement="true" >
            <constraints primaryKey="true" nullable="false"/>
        </column>
        <column name="username" type="varchar(50)">
            <constraints nullable="false"/>
        </column>
    </createTable>

    <loadData
            file="liquibase/data/user.csv"
            separator=";"
            tableName="user">
    </loadData>
</changeSet>

DATABASECHANGELO

数据表,用于记录已经应用的变更集的信息,包括变更集ID、应用时间、应用用户等信息。这个表格是Liquibase用来判断数据库的变更状态,避免重复应用变更集的关键。

CREATE TABLE `DATABASECHANGELOG` (
  `ID` varchar(255) NOT NULL,
  `AUTHOR` varchar(255) NOT NULL,
  `FILENAME` varchar(255) NOT NULL,
  `DATEEXECUTED` datetime NOT NULL,
  `ORDEREXECUTED` int(11) NOT NULL,
  `EXECTYPE` varchar(10) NOT NULL,
  `MD5SUM` varchar(35) DEFAULT NULL,
  `DESCRIPTION` varchar(255) DEFAULT NULL,
  `COMMENTS` varchar(255) DEFAULT NULL,
  `TAG` varchar(255) DEFAULT NULL,
  `LIQUIBASE` varchar(20) DEFAULT NULL,
  `CONTEXTS` varchar(255) DEFAULT NULL,
  `LABELS` varchar(255) DEFAULT NULL,
  `DEPLOYMENT_ID` varchar(10) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

DATABASECHANGELOGLOCK

数据表,用于控制Liquibase在应用变更时的并发访问。当Liquibase应用变更时,它会自动在表中创建一行记录,防止其他进程或线程同时修改数据库。当变更应用完成后,Liquibase会删除这个表格中的记录,以允许其他进程或线程修改数据库。

CREATE TABLE `DATABASECHANGELOGLOCK` (
  `ID` int(11) NOT NULL,
  `LOCKED` bit(1) NOT NULL,
  `LOCKGRANTED` datetime DEFAULT NULL,
  `LOCKEDBY` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


LiquiBase在执行changelog时,会在数据库中插入DATABASECHANGELOG DATABASECHANGELOGLOCK两张表。在执行changelog中的changeSet时,会首先查看DATABASECHANGELOG表,如果已经执行过,则会跳过,如果没有执行过,则执行并记录changelog日志。

changelog中的一个changeSet对应一个事务,在changeSet执行完后commit,如果出现错误则rollback。

changeset及其他标签的配置详见liquibase官方文档

命名规范

在Liquibase中,changeset ID是用于唯一标识数据库变更集的标识符。其命名应该具有唯一性、描述性和规范性,以便于管理和理解数据库变更集。以下是一些Liquibase changeset ID命名的建议:

  1. changeset ID应该是一个唯一的标识符,以确保在不同的变更集之间不会出现冲突。
  2. 一般建议使用数字、字母或下划线的组合来命名changeset ID。
  3. changeset ID应该具有一定的描述性,以便于理解和识别。例如,可以使用数据库对象的名称和变更的简要描述作为changeset ID的一部分。如20230101_001_create_user

Spring整合Liquibase

  1. 项目概览
  1. pom.xml引入依赖
<dependency>
  <groupId>org.liquibase</groupId>
  <artifactId>liquibase-core</artifactId>
</dependency>
  1. 配置application. yml
spring:
  # 示例中使用的是PG数据库
  datasource:
    driver-class-name: org.postgresql.Driver
    url: jdbc:postgresql://127.0.0.1:5432/lenka_dev
    username: postgres
    password: postgres
  # 重点
  liquibase:
    enabled: true
    # 指定配置文件路径
    change-log: classpath:liquibase/master.xml
    # 覆盖本地 ddl dml 注意:若为 true,每次都会重置数据库!!!
    # 默认为false
    drop-first: false
    # 记录版本日志表
    # 默认为databasechangelog,可不指定
    database-change-log-table: databasechangelog
    # 记录版本改变lock表
    # 默认为databasechangeloglock,可不指定
    database-change-log-lock-table: databasechangeloglock
  1. Liquibase xml

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

  <property name="now" value="now()" dbms="h2"/>
  <property name="now" value="now()" dbms="mysql, mariadb"/>

  <property name="floatType" value="float4" dbms="postgresql, h2"/>
  <property name="floatType" value="float" dbms="mysql, oracle, mssql, mariadb"/>
  <property name="clobType" value="clob" dbms="h2"/>
  <property name="clobType" value="clob" dbms="mysql, oracle, mssql, mariadb, postgresql"/>
  <property name="uuidType" value="varchar(36)" dbms="h2, mysql, mariadb"/>

  <include file="liquibase/changelog/20230101_changelog.xml" relativeToChangelogFile="false"/>
</databaseChangeLog>

20230101_changelog.xml

<?xml version="1.0" encoding="utf-8"?>
<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 http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.9.xsd
                        http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">
    <changeSet id="20230101_001_create_user" author="admin">
        <createTable tableName="user">
            <column name="id" type="bigint" autoIncrement="true" >
                <constraints primaryKey="true" nullable="false"/>
            </column>
            <column name="username" type="varchar(50)">
                <constraints nullable="false"/>
            </column>
        </createTable>

        <loadData
                file="liquibase/data/user.csv"
                separator=";"
                tableName="user">
        </loadData>
    </changeSet>
</databaseChangeLog>

user.csv

id;username
1;lekna
2;anty
  1. 启动项目,在数据库中会看到 DATABASECHANGELOG 、DATABASECHANGELOGLOCK 和 user表
  1. 此时我们想在user表中新增一个mobile字段,直接在之前的changeset中添加了字段,如下图所示,然后启动项目看结果


控制台报错

这里涉及到Liquibase版本控制原理

  1. 在Liquibase中,一个Changeset通常由一个唯一的ID和一个作者(Author)组成,并唯一标识了一个Changeset。
  2. Liquibase会对已经执行的changelog的每一个changeSet的内容进行md5计算,生成的值是databasechanglog表的MD5SUM字段;
  3. 当重新启动Liquibase时,会对每个changeSet进行md5值计算,与databasechanglog表中的MD5SUM字段进行对比,如果不一致,说明changeSet值已经被修改,无法启动成功。

Maven Liquibase插件

通过liquibase maven plugin可以实现很多功能。例如:脚本运行,生成文档,数据库差异比较等。

集成Maven

在pom.xml中新增插件配置

<build>
    <plugins>
        <plugin>
            <groupId>org.liquibase</groupId>
            <artifactId>liquibase-maven-plugin</artifactId>
            <version>${liquibase.verison}</version>
            <configuration>
                <!--指定Liquibase的变更日志文件路径,该文件用于定义数据库变更的历史记录和当前版本的状态-->
                <changeLogFile>${project.basedir}/src/main/resources/liquibase/master.xml</changeLogFile>
                <!--changelog文件生成位置-->
                <outputChangeLogFile>${project.basedir}/src/main/resources/liquibase/changelog/changelog-output.xml</outputChangeLogFile>
                <!--指定生成的差异日志文件路径,该文件用于在升级过程中跟踪数据库模式的更改-->
                <diffChangeLogFile>${project.basedir}/src/main/resources/liquibase/changelog/changelog-diff.xml</diffChangeLogFile>
                
                <!--数据库配置-->
                <driver>org.postgresql.Driver</driver>
                <url>jdbc:postgresql://127.0.0.1:5432/lenka_dev</url>
                <!--指定默认模式名称,如果没有指定模式,则将使用此名称-->
                <defaultSchemaName>public</defaultSchemaName>
                <username>postgres</username>
                <password>postgres</password>

                <!--用于差异比较的数据库,以此数据库为准。差异日志存储在diffChangeLogFile指定的路径-->
                <referenceDriver>org.postgresql.Driver</referenceDriver>
                <referenceUrl>jdbc:postgresql://127.0.0.1:5432/lenka_test</referenceUrl>
                <referenceDefaultSchemaName>public</referenceDefaultSchemaName>
                <referenceUsername>postgres</referenceUsername>
                <referencePassword>postgres</referencePassword>
              
                <!--指定是否在控制台上显示详细输出-->
                <verbose>true</verbose>
                <!--指定Liquibase日志记录级别-->
                <logging>debug</logging>
                <!--指定Liquibase要执行的环境上下文,可以是逗号分隔的环境列表。如dev,test -->
                <!--在此示例中,配置了上下文为“!test”,表示不执行与“test”上下文相关的任何操作。-->
                <contexts>!test</contexts>
            </configuration>
        </plugin>
    </plugins>
</build>


配置好maven插件之后,我们就会在maven的插件列表里看到liquibase的插件


下面介绍几个重要的插件

逆向生成xml文件

双击liquibase:generateChangeLog从已有的数据库生成changelog.xml配置信息

执行完成之后就会在上述liquibase插件中配置的outputChangeLogFile路径生成对应的xml文件,如下图所示

比较数据库差异

双击liquibase:diff比较两个数据库 schema 的差异,并生成一个 Liquibase changelog 文件,以便将这些差异应用到目标数据库中。

生成数据库文档

双击liquibase:dbDoc,会生成数据库修改文档,默认会生成到target目录中,如下图所示

在浏览器中打开index.html

发布changelog

双击liquibase:update选项,便可以将修改同步到数据库中。在已运行的项目下,无需重启项目。

释放锁

双击liquibase:releaseLocks选项,释放 Liquibase 对数据库的锁。

在某些情况下,例如当使用 update 命令时,Liquibase 会获取对数据库的锁来防止其他实例对同一个数据库执行更新操作。如果在执行命令后出现异常或其他情况,可能会导致 Liquibase 无法释放数据库上的锁,这可能会导致其他实例无法更新数据库。在这种情况下,你可以手动使用 liquibase:releaseLocks 命令释放数据库上的锁。

执行前

执行后

其他命令

  1. liquibase:rollback:回滚到上一个版本。
  2. liquibase:rollbackCount:回滚到 changelog 中的指定版本号。
  3. liquibase:rollbackToDate:回滚到 changelog 中指定日期时间之前的版本。
  4. liquibase:status:显示当前数据库的状态,包括 changelog 表中的当前版本和已应用的变更集。
  5. liquibase:dropAll:删除所有对象,包括表、视图、约束等。
  6. liquibase:clearCheckSums:清除 changelog 表中所有变更集的校验和。
  7. liquibase:updateSQL:生成 SQL 脚本,用于将数据库更新到当前 changelog 中定义的最新版本。
  8. liquibase:rollbackSQL:生成 SQL 脚本,用于回滚到上一个版本。

Tags:

最近发表
标签列表