网站首页 > 技术文章 正文
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命名的建议:
- changeset ID应该是一个唯一的标识符,以确保在不同的变更集之间不会出现冲突。
- 一般建议使用数字、字母或下划线的组合来命名changeset ID。
- changeset ID应该具有一定的描述性,以便于理解和识别。例如,可以使用数据库对象的名称和变更的简要描述作为changeset ID的一部分。如20230101_001_create_user
Spring整合Liquibase
- 项目概览
- pom.xml引入依赖
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
</dependency>
- 配置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
- 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
- 启动项目,在数据库中会看到 DATABASECHANGELOG 、DATABASECHANGELOGLOCK 和 user表
- 此时我们想在user表中新增一个mobile字段,直接在之前的changeset中添加了字段,如下图所示,然后启动项目看结果
控制台报错
这里涉及到Liquibase版本控制原理
- 在Liquibase中,一个Changeset通常由一个唯一的ID和一个作者(Author)组成,并唯一标识了一个Changeset。
- Liquibase会对已经执行的changelog的每一个changeSet的内容进行md5计算,生成的值是databasechanglog表的MD5SUM字段;
- 当重新启动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 命令释放数据库上的锁。
执行前
执行后
其他命令
- liquibase:rollback:回滚到上一个版本。
- liquibase:rollbackCount:回滚到 changelog 中的指定版本号。
- liquibase:rollbackToDate:回滚到 changelog 中指定日期时间之前的版本。
- liquibase:status:显示当前数据库的状态,包括 changelog 表中的当前版本和已应用的变更集。
- liquibase:dropAll:删除所有对象,包括表、视图、约束等。
- liquibase:clearCheckSums:清除 changelog 表中所有变更集的校验和。
- liquibase:updateSQL:生成 SQL 脚本,用于将数据库更新到当前 changelog 中定义的最新版本。
- liquibase:rollbackSQL:生成 SQL 脚本,用于回滚到上一个版本。
猜你喜欢
- 2025-01-09 精通Spring Boot 3 : 13. Spring Cloud 与 Spring Boot (4)
- 2025-01-09 Spring Boot集成Redis Search快速入门Demo
- 2025-01-09 Spring Boot 3.x嵌入MongoDB 进行测试
- 2025-01-09 java安全之fastjson链分析
- 2025-01-09 MyBatis初级实战之五:一对一关联查询
- 2025-01-09 精通Spring Boot 3 : 8. Spring Boot 测试 (2)
- 2025-01-09 DevSecOps 管道: 使用Jenkins实现安全的多语言应用程序
- 2025-01-09 比较一下JSON与XML两种数据格式?
- 2025-01-09 Java批量导入时,如何去除重复数据并返回结果?
- 2025-01-09 Spring Boot集成Mockito快速入门Demo
- 02-21走进git时代, 你该怎么玩?_gits
- 02-21GitHub是什么?它可不仅仅是云中的Git版本控制器
- 02-21Git常用操作总结_git基本用法
- 02-21为什么互联网巨头使用Git而放弃SVN?(含核心命令与原理)
- 02-21Git 高级用法,喜欢就拿去用_git基本用法
- 02-21Git常用命令和Git团队使用规范指南
- 02-21总结几个常用的Git命令的使用方法
- 02-21Git工作原理和常用指令_git原理详解
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)