boot-admin整合Liquibase实现数据库版本管理

Liquibase 和 Flyway 是两款成熟的、优秀的、开源/商业版的数据库版本管理工具,鉴于 Flyway 的社区版本对 Oracle 数据库支持存在限制,所以 boot-admin 选择整合 Liquibase 提供数据库版本管理能力支持。
Liquibase 开源版使用 Apache 2.0 协议。

Liquibase的适用情形?

  • 在你的项目进行版本升级的时候,大概率情况下数据库也需要同步升级,Liquibase 会自动扫描数据库迁移文件(changeSet),将迁移文件的版本号与历史记录表(changelog )中的版本号进行对比,略过已执行的的迁移文件,顺序执行未执行的新版本迁移文件,最终实现数据库与代码版本相匹配;
  • 当多人协作开发项目的时候,系统源代码可使用 git 保持同步,那么数据库的同步就可交由 liquibase 来保证;
  • 使用 liquibase 可以方便地比较两个数据库的差异;
  • 使用 liquibase 还支持数据库版本回滚。

Liquibase的优点有哪些?

  1. 配置文件支持SQL、XML、JSON 或者 YAML;
  2. 可兼容14种主流数据库如 oracle,mysql 等,支持平滑迁移;
  3. 版本控制按序执行;
  4. 可以用上下文控制sql在何时何地如何执行;
  5. 具备在应用中具有if / then逻辑的能力;
  6. 支持 schema 的变更;
  7. 根据配置文件自动生成sql语句用于预览;
  8. 可重复执行迁移;
  9. 可插件拓展;
  10. 可回滚;
  11. 支持schema方式的多租户(multi-tenant);
  12. 能够在多种数据库类型上具有相同的更改描述;
  13. 生成的数据库历史记录文档;
  14. 能够轻松指定更复杂的多语句更改。

整合要点

boot-admin 是一款采用前后端分离模式、基于 SpringCloud 微服务架构的SaaS后台管理框架。系统内置基础管理、权限管理、运行管理、定义管理、代码生成器和办公管理6个功能模块,集成分布式事务 Seata、工作流引擎 Flowable、业务规则引擎 Drools、后台作业调度框架 Quartz 等,技术栈包括 Mybatis-plus、Redis、Nacos、Seata、Flowable、Drools、Quartz、SpringCloud、Springboot Admin Gateway、Liquibase、jwt、Openfeign、I18n等。

项目源码仓库github
项目源码仓库gitee

引入Maven依赖

<dependency>
    <groupId>org.liquibase</groupId>
    <artifactId>liquibase-core</artifactId>
</dependency>

添加配置

spring:
  liquibase:
    enabled: true
    change-log: classpath:liquibase/master.xml

创建master.xml

在 resources 下创建文件夹 liquibase ,创建文件 master.xml

<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.1.xsd">

    <includeAll path="liquibase/changelogs/" relativeToChangelogFile="false"/>

</databaseChangeLog>

在 liquibase 文件夹下创建 changelogs 和 sql 两个文件夹,如下图所示:

编写数据库变更单元 changeSet

在 resources\liquibase\changelogs 下创建 changeSet 文件,推荐每月一个 xml 文件,文件名格式:【changelog-年度+月份.xml】,如:changelog-202304.xml
常用操作举例:

创建表

    <changeSet author="admin (generated)" id="00001-9">
        <createTable remarks="行政区划表" tableName="TB_ADM_DIV">
            <column name="GUID" remarks="主键" type="NVARCHAR2(38)">
                <constraints nullable="false" primaryKey="true" primaryKeyName="PK_TB_ADM_DIV"/>
            </column>
            <column name="ADM_DIV_CODE" remarks="行政区划代码" type="NVARCHAR2(12)">
                <constraints nullable="false"/>
            </column>
            <column name="ADM_DIV_NAME" remarks="行政区划名称" type="NVARCHAR2(100)">
                <constraints nullable="false"/>
            </column>
            <column name="CREATE_BY" remarks="记录创建者" type="NVARCHAR2(100)">
                <constraints nullable="false"/>
            </column>
            <column name="CREATE_TIME" remarks="记录创建时间" type="${type.datetime}">
                <constraints nullable="false"/>
            </column>
            <column name="MODIFY_BY" remarks="记录最后修改者" type="NVARCHAR2(100)">
                <constraints nullable="false"/>
            </column>
            <column name="MODIFY_TIME" remarks="记录最后修改时间" type="${type.datetime}">
                <constraints nullable="false"/>
            </column>
            <column defaultValueComputed="${now}" name="DATESTAMP" remarks="时间戳" type="${type.datetime}">
                <constraints nullable="false"/>
            </column>
            <column name="ENABLED" remarks="启用状态;ENABLED" type="NVARCHAR2(1)">
                <constraints nullable="false"/>
            </column>
            <column name="DELETED" remarks="删除状态;DELETED" type="NVARCHAR2(1)">
                <constraints nullable="false"/>
            </column>
            <column name="VERSION" remarks="乐观锁" type="${type.int}">
                <constraints nullable="false"/>
            </column>
            <column name="REMARKS" remarks="备注" type="NVARCHAR2(900)"/>
            <column name="TENANT_ID_" remarks="租户ID" type="NVARCHAR2(38)">
                <constraints nullable="false"/>
            </column>
            <column name="PARENT_GUID" remarks="父级GUID" type="NVARCHAR2(38)">
                <constraints nullable="false"/>
            </column>
            <column name="LEAF" remarks="是否末级;YESNO" type="NVARCHAR2(1)">
                <constraints nullable="false"/>
            </column>
            <column name="SORT" remarks="顺序号" type="${type.int}">
                <constraints nullable="false"/>
            </column>
        </createTable>
    </changeSet>

添加表字段

<changeSet author="admin" id="00002-1">
    <addColumn tableName="TB_ADM_DIV">
       <column name="EXT" remarks="扩展" type="VARCHAR(64)"/>
    </addColumn>
</changeSet>

删除表字段

    <changeSet author="admin" id="00002-2">
        <dropColumn tableName="TB_ADM_DIV" columnName="EXT"/>
    </changeSet>

修改表字段说明

    <changeSet author="admin" id="00002-3">
        <setColumnRemarks tableName="TB_ADM_DIV" columnName="EXT" remarks="扩展字段"/>
    </changeSet>

修改表字段类型

    <changeSet author="admin" id="00002-4">
        <modifyDataType tableName="TB_ADM_DIV" columnName="EXT" newDataType="VARCHAR2(2000)"/>
    </changeSet>

创建视图

    <changeSet author="admin (generated)" id="00001-1" dbms="oracle">
        <createView fullDefinition="true" remarks="表和视图" viewName="V_TABLES_MASTER">
            CREATE OR REPLACE FORCE VIEW V_TABLES_MASTER (TABLE_SCHEMA, TABLENAME, TABLETYPE, COMMENTS, TENANT_ID_) AS
            select SYS_CONTEXT('USERENV','CURRENT_SCHEMA') TABLE_SCHEMA,
            t.tname tableName,
            tabtype tabletype,
            f.comments comments,
            'DEMO' TENANT_ID_
            from tab t
            inner join user_tab_comments f
            on t.tname = f.table_name
            where tname != 'DATABASECHANGELOG'
            and tname != 'DATABASECHANGELOGLOCK'
            and tname != 'UNDO_LOG'
        </createView>
    </changeSet>
    <changeSet author="37514 (generated)" id="00000-2" dbms="mysql">
        <createView fullDefinition="true" remarks="表和视图" viewName="V_TABLES_MASTER">
            CREATE OR REPLACE VIEW V_TABLES_MASTER  AS
            SELECT
            TABLE_SCHEMA,
            TABLE_NAME AS TABLENAME,
            case when table_type='BASE TABLE' then 'TABLE' ELSE table_type END AS TABLETYPE,
            TABLE_COMMENT AS COMMENTS,
            'DEMO' TENANT_ID_
            FROM
            information_schema.`TABLES`
            WHERE table_name != 'databasechangeloglock' AND TABLE_NAME != 'databasechangelog' AND TABLE_NAME != 'undo_log'
        </createView>
    </changeSet>

兼容 Oracle 和 Mysql 配置

    <property name="type.datetime" value="date" dbms="oracle"/>
    <property name="type.datetime" value="timestamp" dbms="mysql"/>
    <property name="type.int" value="NUMBER(*, 0)" dbms="oracle"/>
    <property name="type.int" value="INT" dbms="mysql"/>
    <property name="type.decimal" value="NUMBER(*, 2)" dbms="oracle"/>
    <property name="type.decimal" value="DECIMAL" dbms="mysql"/>
    <property name="now" value="SYSDATE" dbms="oracle"/>
    <property name="now" value="now()" dbms="mysql,h2"/>
    <property name="autoIncrement" value="true" dbms="mysql,h2,postgresql,oracle"/>
    <property name="amount" value="decimal(20,2)"/>
    <property name="uuid" value="sys_guid()" dbms="oracle"/>
    <property name="uuid" value="UUID()" dbms="mysql"/>

执行 SQL 文件

    <changeSet id="20000820-003" author="Administrator" dbms="oracle">
        <sqlFile dbms="oracle" path="classpath:/liquibase/sql/seata-undo_log-oracle.sql" />
    </changeSet>
    <changeSet id="20000820-003" author="Administrator" dbms="mysql">
        <sqlFile dbms="mysql" path="classpath:/liquibase/sql/seata-undo_log-mysql.sql" />
    </changeSet>

需将对应 sql 文件放在指定文件夹中。

Liquibase changeSet常用命令清单

add

标签 描述
addAutoIncrement 将一个已存在的列转换为自增
addColunm 增加列
addDefaultValue 对已存在的列增加默认值
addForeignKeyConstraint 对已存在的列增加外键约束
addLookupTable 创建外键关联的表
addNotNullConstraint 对已存在的列增加非空约束
addPrimaryKey 对已存在的列增加主键约束
ddUniqueConstraint 对已存在的列增加主键约束

create

标签 描述
createIndex 创建索引
createProcedure 创建存储过程
createSequence 创建序列
createTable 创建表
createView 创建视图

drop

标签 描述
dropAllForeignKeyConstraints 删除全部的外键约束
dropColumn 删除列
dropDefaultValue 删除默认值设置
dropForeignKeyConstraint 删除某一列的外键约束
dropNotNullConstraint 删除非空约束
dropIndex 删除索引
dropSequence 删除约束
dropProcedure 删除存储过程
dropPrimaryKey 删除主键
dropTable 删除表
dropUniqueConstraint 删除唯一性约束
dropView 删除视图

rename

标签 描述
renameColumn 重命名列
renameSequence 重命名序列
renameTable 重命名表
renameView 重命名视图

sql

标签 描述
sql 原生SQL
sqlFile 引入 SQL 文件

othr

标签 描述 标签 描述
alterSequence 修改序列 customChange 自定义change类型,需要自己实现liquibase.change.custom.CustomSqlChange、liquibase.change.custom.CustomTaskChange接口
delete 删除数据 empty 空操作
executeCommand 执行系统命令,如 mysqldump insert 插入数据
loadData 加载 csv 文件到已存在的表中 loadUpdateData 加载 csv 文件到已存在的表中,但是会判断是否存在,存在更新,否则新增
mergeColumns 将两列值合并在一起,存入新列中 modifyDataType 修改列数据类型
output 记录一条消息并继续执行 setColumnRemarks 列上添加备注
setTableRemarks 表上添加备注 stop 通过消息停止 Liquibase
tagDatabase 将标签应用于数据库以供将来回滚 update 更新数据

原文链接:https://www.cnblogs.com/soft1314/p/17375273.html

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:boot-admin整合Liquibase实现数据库版本管理 - Python技术站

(0)
上一篇 2023年5月5日
下一篇 2023年5月6日

相关文章

  • javaweb前端向后端传值的几种方式总结(附代码)

    以下是对“javaweb前端向后端传值的几种方式总结(附代码)”的详细讲解攻略。 前言 在Web开发中,前端页面需要向后端服务器传递数据以完成后续逻辑的处理,而后端需要获取前端传递的数据进行处理并返回相应的结果。在这个过程中,前后端数据传递是非常重要的,因此准确地传递和获取数据是保证Web应用程序正常运行的基础。接下来,我们将介绍JavaWeb前端向后端传值…

    Java 2023年6月15日
    00
  • SpringBoot集成内存数据库Derby的实践

    请看以下攻略: SpringBoot集成内存数据库Derby实践 Apache Derby是基于Java的内存关系型数据库。这篇文章将介绍如何在Spring Boot应用程序中使用Derby,实现内存数据库的集成,以及用于创建表、插入数据以及检索和删除数据的几个简单示例。 集成Derby 要集成Derby,需要添加以下依赖项到pom.xml中: <de…

    Java 2023年5月20日
    00
  • SpringBoot依赖管理的源码解析

    SpringBoot依赖管理的源码解析 SpringBoot依赖管理包括以下三个方面:依赖注入、自动配置、起步依赖。 1.1 依赖注入 SpringBoot采用了Java注解的方式来实现依赖注入,主要包括以下注解: @Autowired:自动装配,SpringBoot会自动将Bean注入到需要的地方; @Component:将当前类标记为Spring Bea…

    Java 2023年5月19日
    00
  • java日期格式化SimpleDateFormat的使用详解

    Java日期格式化SimpleDateFormat的使用详解 概述 在Java编程中,我们经常需要将日期时间类型的数据格式化成我们需要的字符串格式。Java提供了一个SimpleDateFormat类,可以帮助我们将日期时间类型的数据格式化为指定的字符串格式。 SimpleDateFormat类可以在Java的java.text包中找到,它是一个具有丰富功能…

    Java 2023年5月20日
    00
  • 基于SpringBoot核心原理(自动配置、事件驱动、Condition)

    我将详细讲解基于SpringBoot核心原理的完整攻略,包括自动配置、事件驱动和Condition。 自动配置 SpringBoot通过自动配置(autocconfiguration)的方式,大大减轻了开发人员的工作负担。自动配置就是在应用运行时,根据类路径下的jar包、类的反射信息、注解等信息,自动配置应用所需要的组件和参数,而不需要显示的在代码中进行配置…

    Java 2023年5月15日
    00
  • Java使用动态规划算法思想解决背包问题

    Java 使用动态规划算法思想解决背包问题 什么是动态规划算法 动态规划(Dynamic Programming)是一种解决多阶段决策问题的优化方法。它将问题分解为多个阶段,并针对每个阶段进行决策。每个阶段的决策将会影响后续的阶段,因此需要对每个阶段进行全局最优化的考虑,以确保最终的结果是最优的。 背包问题 背包问题(Knapsack Problem)是常见…

    Java 2023年5月19日
    00
  • JavaScript面向对象三个基本特征实例详解【封装、继承与多态】

    JavaScript面向对象三个基本特征实例详解 在JavaScript中,面向对象编程是一种常用的编程方式,它主要依靠三个基本特征:封装、继承和多态。下面将分别对它们进行详细的说明。 封装 封装是指将数据和行为封装在一个对象中,并对外部提供公共方法进行访问。 下面是一个使用封装的示例: class Person { constructor(name, ag…

    Java 2023年5月23日
    00
  • java教程之java程序编译运行图解(java程序运行)

    我们来详细讲解一下“java教程之java程序编译运行图解(java程序运行)”的完整攻略。 1.什么是Java程序编译 Java程序编译的过程是指将Java源代码(.java文件)编译成Java字节码(.class文件)的过程。在Java编程中,编写的源代码并不能直接运行,需要通过编译成字节码后,才能在Java虚拟机上进行执行。Java编译器可以检查代码中…

    Java 2023年5月20日
    00
合作推广
合作推广
分享本页
返回顶部