2

Liquibase-数据库脚本版本管理控制 - 张铁牛

 2 years ago
source link: https://www.cnblogs.com/ludangxin/p/16676701.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Liquibase-数据库脚本版本管理控制 - 张铁牛 - 博客园

Liquibase是一个用于跟踪、管理和应用数据库变化的开源的数据库重构工具。它将所有数据库的变化(包括结构和数据)都保存在XML文件中,便于版本控制。

Liquibase使参与应用程序发布过程的任何人都可以轻松地:

  • 不依赖于特定的数据库,Liquibase会自动适配目标数据库进行脚本初始化,目前支持至少30种主流数据库。
  • 提供数据库比较功能,比较结果保存在XML中,基于该XML可以用Liquibase轻松部署或升级数据库。
  • 以XML记录/存储数据库变化,其中以authorid唯一标识一个变化(ChangSet),支持数据库变化的合并,因此支持多开发人员同时工作。
  • 在数据库中保存数据库修改历史(DatabaseChangeHistory),在数据库升级时自动跳过已应用的变化(ChangSet)。
  • 提供变化应用的回滚功能,可按时间、数量或标签(tag)回滚已应用的变化。通过这种方式,开发人员可轻易的还原数据库在任何时间点的状态。
  • 可生成数据库修改文档(HTML格式)
  • 提供数据重构的独立的IDE和Eclipse插件
  • 将所有变化(包括结构和数据)存在XML文件中,便于版本控制的工具
    springboot支持,只需要导入依赖。
    application.yml配置(可选)
    不配置,默认去resource/db/changelog下找db.changelog-mastert.yml文件

2. Quick Start

使用步骤

  • step1: 创建一个数据库变更日志(change log)文件。
  • step2: 在变更日志文件内部创建一个变更集(change set)。
  • step3: 通过命令行或构建脚本对数据库进行变更集。
  • step4: 检验数据库中的变更

面向spring开发😉,通过springboot 整合 liquibase 了解其作用。

1759273-20220910145723448-985450665.png

2.1 添加maven依赖



<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.9.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent>

<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.liquibase</groupId> <artifactId>liquibase-core</artifactId> <version>4.8.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> </dependencies>

2.2 application.yaml



spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true username: root password: 123456 liquibase: # 指定配置文件路径 change-log: classpath:db/db.changelog-master.xml # 覆盖本地 ddl dml drop-first: true # 是否启用 enabled: true # 记录版本日志表 database-change-log-table: databasechangelog # 记录版本改变lock表 database-change-log-lock-table: databasechangeloglock

2.3 添加 liquibase xml

db.changelog-master.xml

liquibase 配置文件入口,主要用来引用其他的changelog.xml,如下配置文件中的include,当然也可以使用includeAll来引用整个目录



<?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.8.xsd"> <include file="classpath:db/changelog/changelog-init-0.0.1.xml"/> </databaseChangeLog>

changelog-init-0.0.1.xml

主要记录了ddl的变化信息,比如 如下配置文件中创建了两个表roleuser



<?xml version="1.1" encoding="UTF-8" standalone="no"?> <databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-4.6.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.6.xsd"> <changeSet author="ludangxin" id="1662615627445-2"> <createTable tableName="role" remarks="角色信息表"> <column name="name" remarks="角色名称" type="VARCHAR(255)"/> <column name="role_key" remarks="角色key" type="VARCHAR(255)"/> </createTable> </changeSet> <changeSet author="ludangxin" id="1662615627445-3"> <createTable tableName="user" remarks="用户信息表"> <column name="id" type="INT" remarks="主键"> <constraints nullable="false" primaryKey="true"/> </column> <column name="username" type="VARCHAR(255)" remarks="用户名称"/> <column name="password" type="VARCHAR(255)" remarks="密码"/> <column name="age" type="INT" remarks="性别"/> <column name="sex" type="VARCHAR(255)" remarks="性别"/> <column name="role" type="VARCHAR(255)" remarks="角色"/> <column name="create_time" type="DATETIME" defaultValueComputed="NOW()" remarks="创建时间"/> </createTable> </changeSet> </databaseChangeLog>

2.4 启动测试

项目启动完成后,查看数据库如下图,我们在changelog-init-0.0.1.xml文件中定义的脚本初始化到了数据库中

1759273-20220910145745505-501744643.png

通过该demo快速的完成了springboot 集成 liquibase,且完成数据库的初始化。

2.5 测试changeset版本控制

前提是我们将application.yml中的drop-first置为false,因为drop-first=true相当于每次都重置数据库

此时我们想在user表中新增一个create_by字段,便直接在之前的changeset中添加了字段,如下图所示,然后启动项目看结果

1759273-20220910145820287-1147418847.png

启动时控制台报错信息如下:

报错信息是我们直接修改了changeset后导致md5值与之前的不匹配(直接在之前的changeset中做了修改)

1759273-20220910145839040-1864870455.png

🤔 liquibase如何判断 是同一changeset的?

authorid唯一标识一个变化(ChangSet)

🤔 liquibase是如何进行changeset版本控制的?

Liquibase会对已经执行的changelog的每一个changeSet的内容进行md5计算,生成的值是databasechanglog表的MD5SUM字段。

​ 当重新启动Liquibase时,会对每个changeSet进行md5值计算,与databasechanglog表中的MD5SUM字段进行对比,如果不一致,说明changeSet值已经被修改,无法启动成功。

3. DDL操作

3.1 创建表



<changeSet author="ludangxin" id="20220908-1"> <createTable tableName="order" remarks="订单信息表"> <column name="id" remarks="主键" type="BIGINT"> <constraints nullable="false" primaryKey="true"/> </column> <column name="order_number" remarks="订单编号" type="VARCHAR(255)"/> <column name="user_id" remarks="用户id" type="BIGINT"/> </createTable> </changeSet>

3.2 删除表



<changeSet author="ludangxin" id="20220908-2"> <dropTable tableName="order"/> </changeSet>

3.3 修改表

3.3.1 添加字段



<changeSet author="ludangxin" id="20220908-3"> <addColumn tableName="order"> <column name="status" remarks="订单状态" type="INT" defaultValue="0"/> </addColumn> </changeSet>

3.3.2 删除字段



<changeSet author="ludangxin" id="20220908-4"> <dropColumn tableName="order" columnName="order_number"/> </changeSet>

3.3.3 修改字段



<changeSet author="ludangxin" id="20220908-5"> <renameColumn tableName="order" oldColumnName="status" newColumnName="state" columnDataType="VARCHAR(10)" remarks="订单状态"/> </changeSet>

修改字段类型 不建议使用 因为会把字段的其他信息搞丢,比如字段注释



<changeSet author="ludangxin" id="20220908-7"> <modifyDataType tableName="order" columnName="state" newDataType="INT" /> </changeSet>

4. DML操作

4.1 数据初始化

项目部署难免会有系统内置的数据,这时我们可以通过使用liquibase进行初始化

新建csv文件user-init-0.0.1.csv



"id","username","password","age","sex","role","create_time","create_by" "111","张三","222","23","1","admin","2022-09-08 14:22:33","system" "112","李四","333","26","1","admin","2022-09-08 14:22:33","system" "113","王五","444","25","1","admin","2022-09-08 14:22:33","system"

使用loadData标签进行数据的初始化



<changeSet author="ludangxin" id="20220908-8"> <loadData tableName="user" file="data/user-init-0.0.1.csv" separator="," encoding="UTF-8" relativeToChangelogFile="true"/> </changeSet>

4.2 新增数据



<changeSet author="ludangxin" id="20220908-6"> <insert tableName="order"> <column name="id" valueNumeric="666"/> <column name="user_id" value="2222"/> <column name="state" value="2"/> </insert> <insert tableName="order"> <column name="id" valueNumeric="888"/> <column name="user_id" value="3333"/> <column name="state" value="1"/> </insert> </changeSet>

4.3 初始化总是变动的数据

使用上述的loadData标签加载数据,当数据发生变化时,直接修改csv文件进行发布时,会报错版本不一致。

这时可以使用loadUpdateData标签进行处理,注意的是changeset上需要加参数runOnChange="true"(当数据发生改变时不去校验md5)如下



<changeSet author="ludangxin" id="20220908-9" runOnChange="true"> <loadUpdateData tableName="user" file="data/user-init-0.0.1.csv" primaryKey="id" separator="," encoding="UTF-8" relativeToChangelogFile="true"/> </changeSet>

5. 集成maven

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

5.1 添加 properties

添加properties 文件用来配置liquibase plugin的配置信息。例如 数据库的链接信息,配置文件路径的配置等

liquibase.properties



-- 数据库连接信息 driver=com.mysql.cj.jdbc.Driver url=jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true username=root password=123456 -- liquibse系统表 表名称配置 databaseChangeLogTableName=databasechangelog databaseChangeLogLockTableName=databasechangeloglock -- 输出文件路径配置 outputChangeLogFile=src/main/resources/db/changelog/changelog-output-0.0.1.xml -- liuquibase xml文件路径指定 changeLogFile=src/main/resources/db/db.changelog-master.xml

5.2 修改pom



<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion>

<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.9.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>org.example</groupId> <artifactId>liquibase-demo2</artifactId> <version>1.0-SNAPSHOT</version>

<properties> <liquibase.version>4.8.0</liquibase.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>

<dependency> <groupId>org.liquibase</groupId> <artifactId>liquibase-core</artifactId> <version>${liquibase.version}</version> </dependency>

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency>

<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> </dependencies> <build> <pluginManagement> <plugins> <plugin> <groupId>org.liquibase</groupId> <artifactId>liquibase-maven-plugin</artifactId> <version>${liquibase.version}</version> </plugin> </plugins> </pluginManagement> <plugins> <plugin> <groupId>org.liquibase</groupId> <artifactId>liquibase-maven-plugin</artifactId> <configuration> <!--properties文件路径,该文件记录了数据库连接信息等--> <propertyFile>src/main/resources/db/liquibase.properties</propertyFile> <propertyFileWillOverride>true</propertyFileWillOverride> </configuration> </plugin> </plugins> </build> </project>

6. plugin-逆向生成xml

通过liquibase maven 插件,从已有的数据库生成xml配置信息

1759273-20220910145857558-1312541440.png

通过idea的maven功能,找到 liquibase plugin,双击如图liquibase:generateChangeLog选项,执行完成之后就会在properties文件中配置的outputChangeLogFile路径生成对应的xml文件,如下图所示

1759273-20220910145917602-1709465670.png

7. plugin-生成数据库修改文档

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

1759273-20220910145935059-2067745518.png

访问index.html会展示如下页面,简直应有尽有

1759273-20220910145953061-410172191.png

8. plugin-发布changelog

之前我们对changelog的编辑都需要通过启动项目来运行changelog,有时候我们可能想不重启项目便能将修改发布运行到数据库中

双击liquibase plugin面板中的liquibase:update选项,便可以将修改同步到数据库中

注:这里有个bug(也可能不是bug,我目前还没找到对应的解决办法,如果您有解决方案,🙏),通过plugin发布changelog时,由于我们在db.changelog-masterinclude的是classpath路径,但是通过plugin发布时会报错找不到include的xml文件,此时我们可以通过设置相对路径来解决这个问题,比如<include file="classpath:changelog/changelog-init-0.0.1.xml" relativeToChangelogFile="true"/>,然而这又引发了另外一个问题,plugin和直接启动springboot项目生成的databasechangelog表中的filename字段值不同,导致运行changelog时报错,因为liquibase默认会比较同一filename下的changeset

9. plugin-比较数据库差异

首先使用liquibase diff 功能前,我们在properties中加入参考的数据库 test3配置信息

用于差异比较的数据库,以此数据库为准,生成diff xml



# 对比参考的数据库信息 (用于plugin-diff) referenceUrl=jdbc:mysql://localhost:3306/test3?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true referenceDriver=com.mysql.cj.jdbc.Driver referenceUsername=root referencePassword=123456 # 生成的差异比较xml的输出路径 diffChangeLogFile=src/main/resources/db/changelog/changelog-diff-0.0.1.xml

我们先观察下两个数据库有什么样的差异,再验证生成的diff xml

两个数据库如下,差异都用红色框起来了。

1759273-20220910150006977-1569734449.png

然后再用liquibase插件看下生成的 diff xml信息

双击liquibase plugin面板中的liquibase:diff选项,如下图所示

1759273-20220910150023500-2079560836.png

执行完毕后,查看diff xml 内容如下:

生成的xml文件符合预期,将与test3数据库的差异都生成到了diff xml中

1759273-20220910150041538-709594558.png

__EOF__


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK