一文详解Liquibase如何自动化数据库脚本部署
mhr18 2024-09-29 13:40 25 浏览 0 评论
作者丨Rafal Grzegorczyk
译者丨陈骏
策划丨孙淑娟
【51CTO.com原创稿件】您是否还在手动对数据库执行各种脚本?您是否还在浪费时间去验证数据库脚本的正确性?您是否还需要将脚本合并到某个文件中,以便在每个环境中执行?在面对部署错误时,您是否需要花费数小时去查看数据库的更改,以定位原因?
如今,大多数组织都已经在其应用程序中实施了DevOps的CI/CD流程。不过,其数据库的自动化改造似乎尚未跟上时代。为此,我将向您介绍一种能够实现自动化脚本部署的数据库产品--Liquibase。
Liquibase的基本特点
- 自动化数据库的部署脚本。
- 以相同的方式部署到不同的环境中。
- 能够为每次数据库的更改准备好回滚。
- 能够将部署的所有详细信息集中到一处。
- 最少化的部署错误。
- 方便开发人员针对相同的数据库,进行高效的协同编程。
- 审核逐个更改(请参考下图)。
下面,我将向您展示如何使用Liquibase和Git在Pretius上,自动化数据库的更改过程。
什么是Liquibase?
Liquibase(简称LB)是一个用Java编写的开源工具。它以用户熟悉的格式定义了数据库接口,并能够自动生成特定于数据库的SQL。例如,它将数据库的更改(每一次更改可称为一个更改集)放入被称为changelog的文件中进行管理。通常,Liquibase在数据库架构中会自动创建两张表:
- DATABASECHANGELOG — 存储有关数据库所有更改信息的表。
- DATABASECHANGELOGLOCK — 用于防止用户同时对数据库进行更改。
我将在下面示例中,基于SQL编写变更集,以实现对Oracle数据库的自动化更改过程。
从安装Liquibase开始
请通过链接https://www.liquibase.org/download,选择“仅文件(Just the files)”的方式,下载Liquibase的最新版本。在本文中,我将使用版本:4.3.0 build 09.02.2021。
在将其zip文件夹解压缩后,您必须将新的路径变量(New Path System Variable)设置为计算机上的liquibase-version#bin文件夹。同时,为了使Liquibase正常工作,您还必须安装Java。
通过在CLI工具(在此,我使用的是Visual Studio Code)输入:Liquibase—version,您将能看到:
如果您在文件中使用的是UTF8编码,那么请务必在liquibase.bat文件中添加一行:IF NOT DEFINED JAVA_OPTS set JAVA_OPTS=-Dfile.encoding=UTF–8。
配置项目和Liquibase
下面,让我们来组织各个文件(在本例中,我的GIT存储库放在文件夹HR中)。在各个文件夹中,我们可以在项目开发的过程中创建不同的文件。如果您有其他类型的对象(如“创建或替换”类型),那么只需要用它们创建“同义(synonyms)”文件夹即可。
Liquibase中的文件组织
#path to our master changelog file changeLogFile:Liquibase/update.xml #dbhost and credentials url: jdbc:oracle:thin:@127.0.0.1:1521/XEPDB1 username: HR password: XXXXXX #OJDBC driver localization classpath:Liquibase/ojdbc8.jar #schema, whereLiquibasewill store it’s DATABASECHANGELOG and DATABASECHANGELOGLOCK table(if other than HR, remember to add grants to HR!) liquibaseSchemaName: HR #default SQL file name generated byLiquibase outputFile=output_local.sql #debug mode loglevel=SEVERE #extra option fromLiquibase, we don’t need it for now. liquibase.hub.mode=off
更新了的Liquibase文件夹结构
现在,我们创建一个update.xml文件,并将它放入带有OJDBC文件的、新的 hr/Liquibase文件夹中:
<?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-4.3.xsd"></databaseChangeLog>
使用 Oracle Wallet(可选)
如果您的Oracle数据库托管在Oracle自治数据库上,那么就需要使用Wallet,通过Liquibase去连接它。为此,请下载Wallet并记住其密码。
请将您的WALLET_NAME.ZIP解压到之前创建的HR/Liquibase文件夹中,并编辑HR/liquibase/wallet_name/ojdbc.properties文件:
更改ojdsb.properties
修改后的文件如上图所示。在javax.net.ssl.trustStorePassword和javax.net.ssl.keyStorePassword行,你可以设置ATP Wallet的密码。
在liquibase_local.properties文件中,请编辑URL一行,并设置连接的名称(即,来自Wallet/tnsnames.ora,以及去往Wallet的路径):
url: jdbc:oracle:thin:@rgatp28_high?TNS_ADMIN=liquibase/Wallet_RGATP28
当然,请检查您的sqlnet.ora文件,确保其“SSL_SERVER_DN_MATCH=yes”,且无需改变其他地方。
将Liquibase与数据库连接
如果一切设置正确,我们便可以顺利连接上DEV数据库。让我们从HR文件夹(Liquibase的属性文件位置)处启动CLI,并输入:
Liquibase—defaultsFile=liquibase_dev.properties updateSQL
VSCode终端中的updateSQL命令
其中:
- Liquibase会调用LB的环境路径。
- defaultsFile指定属性文件的名称和位置。如果您将属性文件命名为“liquibase.properties”,那么可以省略此命令。
- updateSQL负责生成SQL脚本(它并不会对数据库执行任何操作)。
几秒钟后,LB将会生成output_file.sql:
生成的output_file.sql
如前所述,如果您在数据库中运行该脚本,它将创建两个表:DATABASECHANGELOG和DATABASECHANGELOGLOCK。下面,让我们通过Liquibase—defaultsFile=liquibase_dev.properties update,来创建这些表。其中的update命令是对数据库执行SQL语句。完成后,您将看到如下结构:
我们需要创建一个changelog文件,并指向包含对象的文件夹。在此,我创建了如下HR/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-4.3.xsd"> <includeAll path="triggers" relativeToChangelogFile="true"/> <includeAll path="views" relativeToChangelogFile="true"/> <includeAll path="types" relativeToChangelogFile="true"/> <includeAll path="package_spec" relativeToChangelogFile="true"/> <includeAll path="package_bodies" relativeToChangelogFile="true"/> </databaseChangeLog>
它指向对象文件夹、及其所有内容。为了将主changelog文件HR/liquibaseupdate.xml设置为指向master.xml文件的路径,您只需添一行:
<include file="./master.xml"/>
在update.xml中的include file="./master.xml"
由于Liquibase始终会从Liquibase_dev.properties文件和update.xml文件处运行,因此我们需要让它能够“看到”所有的文件。
跟踪DML和DDL数据库的更改
我们需要为DML和DDL类型的更改创建一个单独的changelog文件,并将更改集写入其中。为此,我们只需创建一个changelog.sql文件,并输入如下内容,以将其标记为LiquibaseSQL文件:
—Liquibaseformatted sql
将changelog.sql标记为LiquibaseSQL文件
我们通过在master.xml文件中添加如下内容,以指向新的changelog:
指向新的changelog
指向changelog或文件夹的顺序是非常重要的。它需要告知Liquibase在运行SQL时的顺序。我们最好先运行changelog(其中包含了“create table(...)”),然后再运行使用该表的编译包。
下面,让我们在变更集中创建第一个项目表:
—changeset AUTHOR:CHANGESET_NAME —comment OPTIONAL COMMENT YOUR DDL
创建第一个项目表
为了预览到数据库有哪些更改,我们让LB生成对应的SQL文件。
Liquibase—defaultsFile=liquibase_dev.properties updateSQL
由Liquibase生成SQL文件
您可能注意到了,LB通过设置LOCKED = 1,来锁定DATABASECHANGELOGLOCK表。也就是说,当您将脚本运行到DB时,列LOCKED被设置为1。而当另一个用户同时运行LB时,Liquibase将为此等待,直到锁定被放开,再创建一个SHOES表,将日志的更改插入到DATABASECHANGELOG中,并从DATABASECHANGELOGLOCK表中释放掉已有的锁。
如果一切正常,如下脚本会被执行到数据库中:
Liquibase—defaultsFile=liquibase_dev.properties update
接着,表SHOES会被创建出来。
我们也可以查询到谁、为何、以及何时创建了这张表。
跟踪包、视图等其他更改
我们也可以如法创建其他脚本。在此,我通过2个单独的文件,创建了一个SHOES_PKG包。每个文件都是带有附加参数的唯一变更集,并被标记为Liquibase格式的SQL文件。
SHOES_BODY和SHOES_SPEC SQL文件
其中:
- runOnChange:true ——意味着每次更改包时,Liquibase都会针对数据库运行该变更集,也就是编译这个包。
- stripComments:false ——意味着不要去除代码注释。
因此,LB在对数据库进行updateSQL操作时,就会去编译包的规范(package spec)、以及包的主体(package body)。一旦我们在数据库中通过update命令编译这些包,它们都会被记录下来。
通过查看MD5SUM的列值可知,它是变更集的最后一次校验和。也就是说,运行了updateSQL后,所有前期被“挂起”的更改都被执行,而且除了锁定LB表外,LB不会在SQL中生成任何内容。
运用updateSQL检查output_local.sql
现在,让我们改变SHOES_PKG本身,并保存该文件。
更新SHOES_PKG本身
那么该文件的校验和会发生变化,LB将再次编译这个包,并运行更新。
Liquidbase中的更新
数据库中的更新
Liquibase将再次编译这个包,并使用DATABASECHANGELOG表中的实际DATEEXECUTED和新的MD5SUM等变更集,去更新相应的行。
如何在现有软件项目中安装Liquibase?
虽然我们好几种方法可以让Liquibase为现有的数据库实现自动化,但是我在此只向您展示最实用的两种。您可以从中选择最适合实际需求的一种。
当现有的项目中有很多对象时
我们通过在项目的存储库中配置Liquibase,并保留所有文件的基础上,在master.xml文件中添加指向它们的路径。具体而言,在实施Liquibase之前,我创建了2个过程和2个触发器:
P_ADD_JOB_HISTORY P_SECURE_DML TRG_SECURE_EMPLOYEES TRG_UPDATE_JOB_HISTORY
现有的P_ADD_JOB_HISTORY.sql文件
您并不需要将“changeset”或“–Liquibaseformatted sql”添加到文件中。
更新后master.xml中的文件路径
我在自己的master.xml中添加了一个指向PROCEDURES文件夹的路径。
下面,让我们运行LiquibaseupdateSQL,并查看Liquibase会执行什么样的SQL:
Liquibase—defaultsFile=liquibase_dev.properties updateSQL
首次尝试更新SQL
既然我们的数据库中已经有了这些过程和触发器,我们就需要通过ChangelogSync和ChangelogSyncSQL命令,避免重复创建。让我们运行ChangelogSyncSQL,并查看其结果。
Liquibase—defaultsFile=liquibase_dev.properties ChangelogSyncSQL
输出的SQL文件为:
可见,SQL文件只插入了一个DATABASECHANGELOG表。它会告知Liquibase这些对象已经创建好了,不需要再次运行。现在,我们便可以将其插入到Oracle数据库中了:
Liquibase—defaultsFile=liquibase_dev.properties ChangelogSync
此时,在DATABASECHANGELOG表中会有4个新的变更集:
您也许会问,这些奇怪的“raw”ID 是什么?为什么作者又被称为“includeAll”呢?这是因为我们采取了最简单、最快捷的方式,将现有的项目迁移到了Liquibase处,而这些变更集是被自动创建的。
当然,您也可以进行一些更改。例如,在P_ADD_JOB_HISTORY中,只需添加一个changeset,就像您在创建新数据库对象时常做的那样。
更改P_ADD_JOB_HISTORY
然后运行Liquibase的更新命令:
现在,Changeset就带有了合适的作者、ID等信息。
在上面的示例中,我向您展示了添加现有对象(可创建或替换)的简单方法,且无需手动创建变更集。我认为这是将Liquibase安装到拥有数百个对象的、现有数据库中的最佳方式。不过,当涉及到库里有不能被替换的对象(如表格)时,我们需要使用另一种方式。
当现有项目中没有很多对象时
创建或替换的对象
正如前面所描述过的,请添加对象,并在master.xml文件中记下文件夹的路径。接着请运行ChangelogSync,并让Liquibase自动创建raw/includeAll/filename的变更集。
由Liquibase生成的变更集
当然,您也可以采用更好的方法,为每个文件创建一个变更集,如下图所示:
虽然这会需要更多的工作,但是您可以在日志中获得更全面的信息:
针对无法创建或替换的对象,您同样有两种方法:
- 对这些对象不做任何操作,但请记住始终为其中的每个更改(包括:更改表、删除列等)创建变更集,并将其添加到changelog.sql文件中。
- 创建变更集并将它们标记为过去已被执行过。
在此,我们着重讨论第二种方式。由于在实施Liquibase之前我已创建好了EMPLOYEES和JOBS两张表,因此我会在新的文件夹HR/scripts_before_Liquibase中,创建changelog_ddl.sql和changelog_constraints.sql两个changelog文件。此外,我也创建了另一个scripts_before_liquibase.xml文件,并将其指向这两个changelog。其中的“include file”通过优先级的方式,告知Liquibase运行脚本的顺序,即:首先创建表,然后创建约束和索引。
新的scripts_before_liquibase.xml文件
这两个文件能够方便您在表中创建ref_constraint时,避免产生冲突。如下图所示,请记住在master.xml文件中,将路径添加到新创建的XML文件(即HR/script_before_liquibase/scripts_before_liquibase.xml)中。
下面是为各种表和约束创建的变更集。
在添加了所有的变更集之后,我们将它们标记为已执行的状态。
让我们运行ChangelogSyncSQL来进行预览,并让ChangelogSync对数据库执行SQL。
运行ChangeSyncSQL和ChangelogSync
下图展示了ChangelogSync命令执行后,更新了的数据库。至此,我们已大功告成,您也可以选用自己喜欢的方式,通过Liquibase来实现数据库的自动化。
小结
如您所见,通过使用Liquibase,我们可以在数据库更改的发布过程中,跟踪所有的相关内容。其中,需要开发人员遵守如下流程:
- 基于变更集的唯一性,并结合AUTHOR:ID(task)与文件名(带changelog的文件),将变更集添加到changelog中。而且,请不要在没有Liquibase的情况下,更改任何内容。
- 验证待执行的SQL。
- 运行数据库的update命令(记住,应当先运行updateSQL,再执行update命令)。
- 通过检查数据库对象和DATABASECHANGELOG表,验证变更集是否已被执行。
【51CTO原创稿件,合作站点转载请注明原文作者和出处为51CTO.com】
相关推荐
- 甲骨文签署多项大型云协议,其一未来可贡献超300亿美元年收入
-
IT之家7月1日消息,根据甲骨文Oracle当地时间6月30日向美国证券交易委员会(SEC)递交的FORM8-K文件,该企业在始于2025年6月1日的202...
- 甲骨文获TEMU巨额合同,后者大部分基础设施将迁移至Oracle云
-
IT之家6月23日消息,Oracle甲骨文创始人、董事长兼首席技术官LarryEllison(拉里埃里森)在本月早些时候的2025财年第四财季和全财年财报电话会议上表示,Oracle...
- Spring Boot 自定义数据源设置,这些坑你踩过吗?
-
你在使用SpringBoot进行后端开发的过程中,是不是也遇到过这样的问题:项目上线后,数据库连接总是不稳定,偶尔还会出现数据读取缓慢的情况,严重影响了用户体验。经过排查,发现很大一部分原因竟然...
- 一个开箱即用的代码生成器(一个开箱即用的代码生成器是什么)
-
今天给大家推荐一个好用的代码生成器,名为renren-generator,该项目附带前端页面,可以很方便的选择我们所需要生成代码的表。首先我们通过git工具克隆下来代码(地址见文末),导入idea。...
- 低代码建模平台-数据挖掘平台(低代码平台的实现方式)
-
现在来看一下数据连接。·这里是管理数据连接的空间,点击这里可以新增一个数据连接。·输入连接名称,然后输入url,是通过gdbc的方式去连接的数据库,目前是支持mysql、oracle以及国产数据库达梦...
- navicat 17.2.7连接oracle数据库提示加载oracle库失败
-
系统:macOS15.5navicat版本:navicatpremiumlite17.2.7连接oracle测试报错:加载oracle库失败【解决办法】:放达里面找到程序,显示简介里面勾选“使...
- 开源“Windows”ReactOS更新:支持全屏应用
-
IT之家6月17日消息,ReactOS团队昨日(6月16日)在X平台发布系列推文,公布了该系统的最新进展,包括升级Explorer组件,支持全屏应用,从Wine项目引入了...
- SSL 推出采用全模拟内置混音技术的模拟调音台Oracle
-
英国调音台传奇品牌SolidStateLogic宣布推出Oracle——一款采用全模拟内置混音技术的调音台,在紧凑的AWS尺寸机箱内集成了大型调音台的功能。该调音台提供24输入和...
- 47道网络工程师常见面试题,看看有没有你不会的!
-
你们好,我的网工朋友。网络工程师面试的时候,都会被问到什么?这个问题其实很泛,一般来说,你肯定要先看明白岗位需求写的是什么。基本上都是围绕公司需要的业务去问的。但不可否认的是,那些最基础的概念,多少也...
- 汉得信息:发布EBS系统安装启用JWS的高效解决方案
-
e公司讯,从汉得信息获悉,近日,微软官方宣布InternetExplorer桌面应用程序将于2022年6月15日正式停用。目前大部分客户都是使用IE浏览器打开EBS的Form界面,IE停用后,只能使...
- 36.9K star ! 推荐一个酷炫低代码开发平台!功能太强!
-
前言最近在逛github,看看能不能搜罗到一些对自己有帮助的开源软件。不经意间看到一个高star的java开源项目:jeecg-boot。进入在线演示版一看,感叹实在是太牛了!此开源项目不管是给来学习...
- Linux新手入门系列:Linux下jdk安装配置
-
本系列文章是把作者刚接触和学习Linux时候的实操记录分享出来,内容主要包括Linux入门的一些理论概念知识、Web程序、mysql数据库的简单安装部署,希望能够帮到一些初学者,少走一些弯路。注意:L...
- 手把手教你在嵌入式设备中使用SQLite3
-
摘要:数据库是用来存储和管理数据的专用软件,使得管理数据更加安全,方便和高效。数据库对数据的管理的基本单位是表(table),在嵌入式linux中有时候它也需要用到数据库,听起来好难,其实就是几个函数...
- JAVA语言基础(java语言基础知识)
-
一、计算机的基本概念什么是计算机?计算机(Computer)全称:电子计算机,俗称电脑。是一种能够按照程序运行、自动高速处理海量数据的现代化智能电子设备。由硬件和软件组成、没有安装过任何软件的计算机称...
- 再见 Navicat!一款开源的 Web 数据库管理工具!
-
大家好,我是Java陈序员。在日常的开发工作中,常常需要与各种数据库打交道。而为了提高工作效率,常常会使用一些可视化工具进行操作数据库。今天,给大家介绍一款开源的数据库管理工具,无需下载安装软件,基...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- 甲骨文签署多项大型云协议,其一未来可贡献超300亿美元年收入
- 甲骨文获TEMU巨额合同,后者大部分基础设施将迁移至Oracle云
- Spring Boot 自定义数据源设置,这些坑你踩过吗?
- 一个开箱即用的代码生成器(一个开箱即用的代码生成器是什么)
- 低代码建模平台-数据挖掘平台(低代码平台的实现方式)
- navicat 17.2.7连接oracle数据库提示加载oracle库失败
- 开源“Windows”ReactOS更新:支持全屏应用
- SSL 推出采用全模拟内置混音技术的模拟调音台Oracle
- 47道网络工程师常见面试题,看看有没有你不会的!
- 汉得信息:发布EBS系统安装启用JWS的高效解决方案
- 标签列表
-
- oracle位图索引 (74)
- oracle批量插入数据 (65)
- oracle事务隔离级别 (59)
- oracle 空为0 (51)
- oracle主从同步 (55)
- oracle 乐观锁 (51)
- redis 命令 (78)
- php redis (88)
- redis 存储 (66)
- redis 锁 (69)
- 启动 redis (66)
- redis 时间 (56)
- redis 删除 (67)
- redis内存 (57)
- redis并发 (52)
- redis 主从 (69)
- redis 订阅 (51)
- redis 登录 (54)
- redis 面试 (58)
- 阿里 redis (59)
- redis 搭建 (53)
- redis的缓存 (55)
- lua redis (58)
- redis 连接池 (61)
- redis 限流 (51)