Liquibase 是一个用于跟踪、管理和应用数据库变化的开源的数据库重构工具。它将所有数据库的变化(包括结构和数据)都保存在 changelog文件中,便于版本控制,它的目标是提供一种数据库类型无关的解决方案,通过执行 schema 类型的文件来达到迁移。

Liquibase 特性

Liquibase 具备如下特性:

  • 支持几乎所有主流的数据库,如 MySQL, PostgreSQL, Oracle, Sql Server, DB2 等;
  • 支持多开发者的协作维护;
  • 日志文件支持多种格式,如 XML, YAML, JSON, SQL等;
  • 支持上下文相关逻辑
  • 生成数据库变更文档
  • 支持多种运行方式,如命令行、Spring 集成、Maven 插件、Gradle 插件等。

更多详情介绍,请查阅 Liquibase 官方文档

Spring Boot 集成 Liquibase

添加依赖

因为 Spring Boot 已经内置支持整合 Liquibase,我们只需要在项目工程中引入 Liquibase 的依赖进行配置即可。

<dependency><groupId>org.liquibase</groupId><artifactId>liquibase-core</artifactId><version>3.6.3</version>
</dependency>
复制代码

配置 application 文件

在 classpath 中配置 application.properties 或 application.yml 文件,

# 启用liquibase
liquibase.enabled=true
# 存储变化的文件(changelog)位置
liquibase.change-log=classpath:sample_change.sql
# 检查存储变化的文件是否存在
liquibase.check-change-log-location=true
# 分环境执行,若在 changelog 文件中设置了对应 context 属性,则只会执行与 dev 对应值的 changeset
liquibase.contexts=dev
# 执行前首先删除数据库,默认 false。若设置为 true,则执行变更前,会先删除目标数据库,请谨慎
liquibase.dropFirst=false
# 执行更新时将回滚 SQL 写入的文件路径
liquibase.rollback-file=
# 如果使用工程已配置的 datasource 数据源,则以下三个数据库连接参数可不配置
## 访问数据库的连接地址
liquibase.url=jdbc:mysql://10.10.4.41:3306/test?useUnicode=true&characterEncoding=utf-8
# 访问数据库的用户名
liquibase.user=test
# 访问数据库的密码
liquibase.password=test复制代码

注意:如果使用工程已配置的 datasource 数据源,则 liquibase.url、liquibase.userliquibase.password这个三个参数可不配置,目标数据源即为工程已配置好的数据源。因为 Spring 会自动为 liquibase 获取可用的数据源,详情可查看这个类:org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration

编写存储变更的 changelog 文件

目前 Liquibase 支持 XML、YAML、JSON 和 SQL 格式四种格式的 changelog 文件。为了方便和直观,下面以基于 SQL 格式编写 changelog 文件:sample_change.sql

--liquibase formatted sql--changeset zhouyi:1
-- 创建用户表
CREATE TABLE `user` (`id` int(20) NOT NULL AUTO_INCREMENT,`name` varchar(50) NOT NULL,`age` int(10) NOT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;--rollback drop table user;--changeset zhouyi:2
insert into user(id, name, age) values(1,'张三',29);
insert into user(id, name, age) values(2,'李四',20);
复制代码

启动 Spring Boot 应用后,可以从日志看到输出:

2019-03-27 13:13:16.439 [main] [] INFO  liquibase.executor.jvm.JdbcExecutor.info:42 - DELETE FROM test.DATABASECHANGELOGLOCK
2019-03-27 13:13:16.442 [main] [] INFO  liquibase.executor.jvm.JdbcExecutor.info:42 - INSERT INTO test.DATABASECHANGELOGLOCK (ID, `LOCKED`) VALUES (1, 0)
2019-03-27 13:13:16.506 [main] [] INFO  liquibase.executor.jvm.JdbcExecutor.info:42 - SELECT `LOCKED` FROM test.DATABASECHANGELOGLOCK WHERE ID=1
2019-03-27 13:13:16.586 [main] [] INFO  liquibase.lockservice.StandardLockService.info:42 - Successfully acquired change log lock
2019-03-27 13:13:16.697 [main] [] INFO  liquibase.changelog.StandardChangeLogHistoryService.info:42 - Creating database history table with name: test.DATABASECHANGELOG
2019-03-27 13:13:16.700 [main] [] INFO  liquibase.executor.jvm.JdbcExecutor.info:42 - CREATE TABLE test.DATABASECHANGELOG (ID VARCHAR(255) NOT NULL, AUTHOR VARCHAR(255) NOT NULL, FILENAME VARCHAR(255) NOT NULL, DATEEXECUTED datetime NOT NULL, ORDEREXECUTED INT NOT NULL, EXECTYPE VARCHAR(10) NOT NULL, MD5SUM VARCHAR(35) NULL, `DESCRIPTION` VARCHAR(255) NULL, COMMENTS VARCHAR(255) NULL, TAG VARCHAR(255) NULL, LIQUIBASE VARCHAR(20) NULL, CONTEXTS VARCHAR(255) NULL, LABELS VARCHAR(255) NULL, DEPLOYMENT_ID VARCHAR(10) NULL)
2019-03-27 13:13:17.570 [main] [] INFO  liquibase.executor.jvm.JdbcExecutor.info:42 - SELECT COUNT(*) FROM test.DATABASECHANGELOG
2019-03-27 13:13:17.575 [main] [] INFO  liquibase.changelog.StandardChangeLogHistoryService.info:42 - Reading from test.DATABASECHANGELOG
2019-03-27 13:13:17.579 [main] [] INFO  liquibase.executor.jvm.JdbcExecutor.info:42 - SELECT * FROM test.DATABASECHANGELOG ORDER BY DATEEXECUTED ASC, ORDEREXECUTED ASC
2019-03-27 13:13:17.585 [main] [] INFO  liquibase.executor.jvm.JdbcExecutor.info:42 - SELECT COUNT(*) FROM test.DATABASECHANGELOGLOCK
2019-03-27 13:13:17.678 [main] [] INFO  liquibase.executor.jvm.JdbcExecutor.info:42 - CREATE TABLE `user` (`id` int(20) NOT NULL AUTO_INCREMENT,`name` varchar(50) NOT NULL,`age` int(10) NOT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
2019-03-27 13:13:17.935 [main] [] INFO  liquibase.changelog.ChangeSet.info:42 - Custom SQL executed
2019-03-27 13:13:17.937 [main] [] INFO  liquibase.changelog.ChangeSet.info:42 - ChangeSet classpath:sample_change.sql::1::zhouyi ran successfully in 297ms
2019-03-27 13:13:17.938 [main] [] INFO  liquibase.executor.jvm.JdbcExecutor.info:42 - SELECT MAX(ORDEREXECUTED) FROM test.DATABASECHANGELOG复制代码

从数据库中可以看到变化,首次运行新增了 3 张表,

其中DATABASECHANGELOGDATABASECHANGELOGLOCK 表是 Liquibase 自动生成的,而 user 表是执行我们编写的 changeset变更集后生成的,并且也已经执行了第 2 个变更集,插入了两条数据。

SQL 格式的 changelogs 文件

SQL 格式的 changelog 文件使用 SQL 注释作为元数据,为确保这个文件被 Liquibase 识别为 changelog文件,,SQL 文件必须以以下注释开头:

--liquibase formatted sql
复制代码

changeset 变更

SQL 格式的 changelog 文件中在变更的 SQL 前需要加上以下注释,表示为一个 changeset变更集:

--changeset author:id attribute1:value1 attribute2:value2 [...]
复制代码

在之前的 sample_change.sql 文件中编写了两条 changeset (变更集),

变更集 changeset 是通过 author + id 的方式来保证唯一性,如以上 zhouyi:1zhouyi:2 两条表更集。

变更集提供以下属性:

属性 说明
stripComments 设置为 true 可在执行之前删除 SQL 中的任何注释, 否则为 false。如果未设置, 则默认值为 true
splitStatements
endDelimiter 应用于语句结尾的分隔符。默认为“;”,也可以设置为“”
runAlways 在每次运行时执行变更集, 即使之前已运行
runOnChange 在首次看到更改并每次更改变更集时执行更改
context 如果在运行时传递了特定上下文, 则执行更改。任何字符串都可以用于上下文名称, 并且大小写不敏感。
logicalFilePath 用于在创建变更集的唯一标识符时重写文件名和路径。移动或重命名更改日志时所必需。
labels 标签是对变更集进行分类的通用方法集类似上下文, 但工作方式正好相反。如果不是在运行时定义一组上下文, 然后在变更集中定义一个匹配表达式, 而是在上下文中定义一组标签, 在运行时定义一个匹配表达式。
runInTransaction 变更集是否应作为单个事务运行 (如果可能),默认值为 true。请注意此属性,如果设置为 false, 并且通过运行包含多个语句的变更集部分发生错误, 则 liquibase 数据库的 databasechangeloglock 表将处于无效状态
failOnError 如果在执行变更集时发生错误, 迁移是否应返回失败
dbms 要用于该变更集的数据库的类型。当迁移步骤运行时, 它将根据此属性检查数据库类型,如:oracle、mysql
logicalFilePath 在数据库 databasechangeloglock 中设置逻辑文件路径, 而不是在执行 liquibase 的 sql 物理文件位置。

前置条件

可以为每个变更集指定先决条件。目前, 仅支持 SQL 检查前置条件。

--preconditions onFail:HALT onError:HALT
--precondition-sql-check expectedResult:0 SELECT COUNT(*) FROM my_table
复制代码

回滚操作

变更集可能包括回滚变更集时要应用的语句。回滚声明也是使用表注释。

--rollback SQL STATEMENT
复制代码

例如在前面编写的 changelog 文件中的第一个 changeset:

--changeset zhouyi:1
-- 创建用户表
CREATE TABLE `user` (`id` int(20) NOT NULL AUTO_INCREMENT,`name` varchar(50) NOT NULL,`age` int(10) NOT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;--rollback drop table user;
复制代码

首先的变更的 SQL 含义是新建一个 user 表,回滚的 SQL 则表示删除新建的 user 表。

Liquibase 最佳实践

下面介绍可应用于项目的一些最佳实践。

一个变更集只设置一次更改

尽可能地避免对一个变更集进行多次更改,以避免自动提交 SQL 语句而可能使数据库处于非预期状态。 如 --changeset zhouyi:1 变更集,只新建一张 user 表,后面不再修改该变更集,如果需要变更,可以新增一条变更集。

变更集的 ID

选择适合您的方法。有的人是使用从 1 开始的序列号, 并且在更改日志中是唯一的,也有些人选择一个描述性的名称(例如:new-address-table

总是考虑回滚

尽量尝试以可以回滚的方式编写变更集,如 --changeset zhouyi:1 变更集新建一个 user 表,在后面跟上回滚的 SQL, --rollback drop table user;

为变更集添加注释

尽量为每一个变更集条目增加注释,如 -- 创建用户表

开发人员使用流程

  • 使用您最喜欢的 IDE 或编辑器, 创建一个包含更改的新本地更改集;
  • 运行 Liquibase 以执行新的变更集 (这将测试 SQL 代码);
  • 在应用程序代码中执行相应的更改 (例如, Java 代码);
  • 测试验证新的应用程序代码以及数据库更改;
  • 提交变更集和应用程序代码。

Spring Boot 简单集成 Liquibase相关推荐

  1. Spring Boot 工程集成全局唯一ID生成器 Vesta

    2019独角兽企业重金招聘Python工程师标准>>> 本文内容脑图如下: 文章共 760字,阅读大约需要 2分钟 ! 概 述 在前一篇文章 <Spring Boot工程集成全 ...

  2. Spring Boot + Shiro 集成

    2019独角兽企业重金招聘Python工程师标准>>> Spring Boot + Shiro 集成 Shiro 是一个流行的 Java 安全框架. 其实 Spring 有一个 Sp ...

  3. Spring Boot 快速集成第三方登录功能

    Spring Boot 快速集成第三方登录功能 前言 此 demo 主要演示 Spring Boot 项目如何使用 史上最全的第三方登录工具 - JustAuth 实现第三方登录,包括 QQ 登录.G ...

  4. 【Spring Boot组件集成实战】集成Kaptcha谷歌验证码

    更多精彩内容,请访问 Spring Boot组件集成实战专栏 ! 推荐项目:一套基于Spring Boot+Layui的内容管理系统/快速开发脚手架(含完整的开发文档.演示网址等) 文章目录 1. 验 ...

  5. 在spring boot中集成Swagger

    Swagger 在spring boot中集成Swagger 新建一个swagger项目 maven依赖 <!-- https://mvnrepository.com/artifact/io.s ...

  6. Spring/Spring boot正确集成Quartz及解决@Autowired失效问题

    Spring/Spring boot正确集成Quartz及解决@Autowired失效问题 参考文章: (1)Spring/Spring boot正确集成Quartz及解决@Autowired失效问题 ...

  7. SpringBoot2.x系列教程(六十六)Spring Boot快速集成RocketMQ实战教程

    前言 RocketMQ是目前主流的消息中间件之一,并且自身就支持分布式功能.最初由阿里巴巴团队开发,并且经历过双十一等海量消息场景的考验,后捐赠给Apache开源基金会,这也是为什么我们经常听说Roc ...

  8. SpringBoot实战(十四):Spring Boot Admin 集成安全模块

    强烈推荐一个大神的人工智能的教程:http://www.captainbed.net/zhanghan [前言] Spring Boot Admin做为生产级的监控工具,必然不能随便让人去操作以免误操 ...

  9. Swagger UI 与 Spring Boot 的集成

    Swagger UI 用于生成交互式 API 文档,让您可以直接在浏览器中尝试 REST 服务调用. 在本指南中,让我们构建一个简单的 Spring Boot REST 服务并将 Swagger UI ...

最新文章

  1. 『前端干货篇』:你不知道的Stylus
  2. node学习准备工作1 --- nvm下载、终端环境iterm2配置
  3. SAP OData 后台ETAG校验逻辑
  4. python新闻聚合_使用python对数据进行高效处理,包你玩转分组聚合
  5. 通过rtcwake命令设置系统S3(休眠到内存)/S4(挂起到硬盘)一段时间后自动唤醒
  6. java容器类1:Collection,List,ArrayList,LinkedList深入解读
  7. linux测试有效组,软件测试:三分钟掌握Linux命令之用户用户组命令(必读系列三)...
  8. java 12_为什么在Java(高低)/ 2是错误但(高低) 1不是?
  9. Ubuntu系统重装 -- 制作启动盘、装机过程问题、环境配置
  10. oracle 独占更新,Oracle的共享封锁 独占封锁和共享更新封锁 (3)
  11. 信息学奥赛一本通1003:对齐输出
  12. 关于如何使用原生实现表格固定列,纯 CSS 实现
  13. C++/OpenCV实现图像目标识别与分类
  14. Xavier 下GMSL相机ROS驱动发布CompressedImage消息(基于NVJPG硬件编码)
  15. 梅森数-形如2n−1的素数称为梅森数
  16. 功能测试——抓包工具(fiddler)
  17. burn suite启动_Microsoft计划(最终)启动Web Office Suite
  18. 数字科技行业的“挖井人”:京东数科不做一锤子买卖
  19. SAP MDG和SAP MDM的区别
  20. EasyFloat:浮窗从未如此简单

热门文章

  1. python取列表前几个元素_Python 获取list(列表)前n个不重复元素
  2. mysql 事务 数量_如何知道数据库创建以来并发事务的最大数量
  3. oracle取消dataguard,【DataGuard】Oracle DataGuard 数据保护模式切换
  4. sublime text3安装python插件和flake8_让你的代码符合PEP8标准——sublime text 2 安装及使用 Python Flake8 Lint 插件...
  5. r怎么保存html文件,leaflet - 为什么在已保存的html文件中缺少传单地图上的杂项,但在Rstudio浏览器中可以正常打印呢? - 堆栈内存溢出...
  6. python划分数据集_Python数据集切分实例
  7. 学习MSCKF笔记——真实状态、标称状态、误差状态
  8. 完成U-net细胞分割的一些准备
  9. vue指令写在html中的原理,详解Vue中的MVVM原理和实现方法
  10. 高级用户 java_java高级-基本