Spring Boot 简单集成 Liquibase
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.user
和liquibase.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 张表,
其中DATABASECHANGELOG
和 DATABASECHANGELOGLOCK
表是 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:1
和 zhouyi: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相关推荐
- Spring Boot 工程集成全局唯一ID生成器 Vesta
2019独角兽企业重金招聘Python工程师标准>>> 本文内容脑图如下: 文章共 760字,阅读大约需要 2分钟 ! 概 述 在前一篇文章 <Spring Boot工程集成全 ...
- Spring Boot + Shiro 集成
2019独角兽企业重金招聘Python工程师标准>>> Spring Boot + Shiro 集成 Shiro 是一个流行的 Java 安全框架. 其实 Spring 有一个 Sp ...
- Spring Boot 快速集成第三方登录功能
Spring Boot 快速集成第三方登录功能 前言 此 demo 主要演示 Spring Boot 项目如何使用 史上最全的第三方登录工具 - JustAuth 实现第三方登录,包括 QQ 登录.G ...
- 【Spring Boot组件集成实战】集成Kaptcha谷歌验证码
更多精彩内容,请访问 Spring Boot组件集成实战专栏 ! 推荐项目:一套基于Spring Boot+Layui的内容管理系统/快速开发脚手架(含完整的开发文档.演示网址等) 文章目录 1. 验 ...
- 在spring boot中集成Swagger
Swagger 在spring boot中集成Swagger 新建一个swagger项目 maven依赖 <!-- https://mvnrepository.com/artifact/io.s ...
- Spring/Spring boot正确集成Quartz及解决@Autowired失效问题
Spring/Spring boot正确集成Quartz及解决@Autowired失效问题 参考文章: (1)Spring/Spring boot正确集成Quartz及解决@Autowired失效问题 ...
- SpringBoot2.x系列教程(六十六)Spring Boot快速集成RocketMQ实战教程
前言 RocketMQ是目前主流的消息中间件之一,并且自身就支持分布式功能.最初由阿里巴巴团队开发,并且经历过双十一等海量消息场景的考验,后捐赠给Apache开源基金会,这也是为什么我们经常听说Roc ...
- SpringBoot实战(十四):Spring Boot Admin 集成安全模块
强烈推荐一个大神的人工智能的教程:http://www.captainbed.net/zhanghan [前言] Spring Boot Admin做为生产级的监控工具,必然不能随便让人去操作以免误操 ...
- Swagger UI 与 Spring Boot 的集成
Swagger UI 用于生成交互式 API 文档,让您可以直接在浏览器中尝试 REST 服务调用. 在本指南中,让我们构建一个简单的 Spring Boot REST 服务并将 Swagger UI ...
最新文章
- 『前端干货篇』:你不知道的Stylus
- node学习准备工作1 --- nvm下载、终端环境iterm2配置
- SAP OData 后台ETAG校验逻辑
- python新闻聚合_使用python对数据进行高效处理,包你玩转分组聚合
- 通过rtcwake命令设置系统S3(休眠到内存)/S4(挂起到硬盘)一段时间后自动唤醒
- java容器类1:Collection,List,ArrayList,LinkedList深入解读
- linux测试有效组,软件测试:三分钟掌握Linux命令之用户用户组命令(必读系列三)...
- java 12_为什么在Java(高低)/ 2是错误但(高低) 1不是?
- Ubuntu系统重装 -- 制作启动盘、装机过程问题、环境配置
- oracle 独占更新,Oracle的共享封锁 独占封锁和共享更新封锁 (3)
- 信息学奥赛一本通1003:对齐输出
- 关于如何使用原生实现表格固定列,纯 CSS 实现
- C++/OpenCV实现图像目标识别与分类
- Xavier 下GMSL相机ROS驱动发布CompressedImage消息(基于NVJPG硬件编码)
- 梅森数-形如2n−1的素数称为梅森数
- 功能测试——抓包工具(fiddler)
- burn suite启动_Microsoft计划(最终)启动Web Office Suite
- 数字科技行业的“挖井人”:京东数科不做一锤子买卖
- SAP MDG和SAP MDM的区别
- EasyFloat:浮窗从未如此简单
热门文章
- python取列表前几个元素_Python 获取list(列表)前n个不重复元素
- mysql 事务 数量_如何知道数据库创建以来并发事务的最大数量
- oracle取消dataguard,【DataGuard】Oracle DataGuard 数据保护模式切换
- sublime text3安装python插件和flake8_让你的代码符合PEP8标准——sublime text 2 安装及使用 Python Flake8 Lint 插件...
- r怎么保存html文件,leaflet - 为什么在已保存的html文件中缺少传单地图上的杂项,但在Rstudio浏览器中可以正常打印呢? - 堆栈内存溢出...
- python划分数据集_Python数据集切分实例
- 学习MSCKF笔记——真实状态、标称状态、误差状态
- 完成U-net细胞分割的一些准备
- vue指令写在html中的原理,详解Vue中的MVVM原理和实现方法
- 高级用户 java_java高级-基本