- http://www.liquibase.org/ 官网
- http://www.mamicode.com/info-detail-2430503.html 码迷【精】
- https://segmentfault.com/a/1190000016641122 思否
- http://www.tianshouzhi.com/api/tutorials/springboot/366 田守枝
- http://www.liquibase.org/documentation/xml_format.html 官网
- https://blog.csdn.net/isyoungboy/article/details/84287389
- https://www.cnblogs.com/lywJ/p/10715343.html 数据迁移写法
- http://www.cnblogs.com/itrena/p/5927143.html 预判断条件;
- https://www.ibm.com/developerworks/cn/java/j-ap08058/index.html#artrelatedtopics IBM
最近,就是昨天,在项目上线前一天,因为本次上线涉及到修改字段的问题,本来以往都是jpa实体类加属性,然后自动生成表字段,然后手动将数据库字段迁移,然后领导就突然要求本次上线数据库修改,必须通过Liquibase来管理。时间只有一天,对没错,一天,在此之前是一个没听过Liquibase的状态的我,心中十万个策马奔腾。
本来,大概看了一下博客,以为这个东西很容易搞定,也给老大承诺了,一天内可以整合进项目,然后,然后我就草了,经历了入职以来最不浑水摸鱼的一天,虽然在整合,部署,上线踩了很多坑【两点上线完】,但是感觉这样紧张的节奏,学习效率还是很高的,下面简单分享我的整合过程,因为我也看了不少Liquibase的博客,总体感觉一是太杂乱,二是没有完整的一篇springboot+gradle+liqubase的博客,我希望通过这个实战经历简单的让大家上手Liquibase。
1.项目结构
eg:
忽略中间白色空隙
2.配置gradle
不用看那些maven管理工具里面那些添加liquibase插件之类的东西,入门的话,那些东西只能更让我们晕头转向
// https://mvnrepository.com/artifact/org.liquibase/liquibase-core
runtimeOnly('org.liquibase:liquibase-core:3.6.2') {
exclude(module: 'logback-classic')
}
runtimeOnly("com.inspur.cloud:liquibase-schema:3.6")
-
坑一:此处因为liquibase中也有日志相关jar包,所以容易和项目中其他日志jar包冲突,如果出现这个问题,排除一下liquibase中的jar就行,就是exclude那个东西
-
坑二:注意引包前的runtimeOnly和compile的区别,这个回头我学习学习,再单独搞个博客吧,因为从maven仓库引入的是compile,但是我们项目里也是报错的,换成 runtime就没这个问题了
3.application.yml
spring:
#数据库相关的配置
datasource:
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=false
username: root
password: root
# jpa配置
jpa:
show-sql: false
hibernate:
ddl-auto: none
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
# liquibase配置
liquibase:
enabled: true
change-log: "classpath:/db/changelog/db.changelog-master.yaml"
contexts: dev
上面配置中药注意四个点:
- jpa配置的ddl-auto:设置为none ,否则项目启动时候,若bean里新增了属性,jpa还会根据实体bean来给数据库增加字段
- liquibase的enabled设置为true,表示开启liquibase管理功能
- change-log: 表示liquibase的主配置文件的路径【注:java项目中classpath理解】
- context:表示liquibase引用的脚本的上下文,要是项目中多个环境的话【比如,研发,测试,生产等】可以配置这个,否则请略过
- spring.liquibase.change-log 配置文件的路径,默认值为 classpath:/db/changelog/db.changelog-master.yaml
- spring.liquibase.check-change-log-location 检查 change log的位置是否存在,默认为true.
- spring.liquibase.contexts 用逗号分隔的运行环境列表。
- spring.liquibase.default-schema 默认数据库 schema
- spring.liquibase.drop-first 是否先 drop schema(默认 false)
- spring.liquibase.enabled 是否开启 liquibase(默认为 true)
- spring.liquibase.password 数据库密码
- spring.liquibase.url 要迁移的JDBC URL,如果没有指定的话,将使用配置的主数据源.
- spring.liquibase.user 数据用户名
- spring.liquibase.rollback-file 执行更新时写入回滚的 SQL文件
4.启动项目
配置完上面这些东西,直接启动项目,启动项目会发现类似下面的报错信息,不要怕,就是没有找到liquibase的主配置文件:
Error creating bean with name 'org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration$LiquibaseConfiguration'
Cannot find changelog location: class path resource [config/liquibase/master_changelog.xml] (please add changelog or check your Liquibase configuration)
5.创建这个缺少的master_changelog.xml
这个时候要注意了,这个master_changelog.xml文件的位置就取决于上面第三步中application.yml中liquibase.change_log的配置
在我的项目中就是这样的:
此时,你的项目中,如果你只希望通过这一个配置文件作为liquibase的配置脚本,那也就够了,可以直接将你的sql,或者xml写在master_changelog.xml中就可以了。
但是,如果是公司项目的话,你后期可能会有多个这种配置文件,你可以通过分类,来将每次的liquibase脚本放在每个文件夹里,在我的项目中,是以月份来区分的,比如后期这种脚本多了之后,项目会是这个样子:
每个文件夹里都是一个小的liquibase配置脚本
6.在master_changelog.xml中引入子脚本
databaseChangeLog:
- include:
file: db/changelog/eip/mysql/t201905/2019050901-ddl-init-zerah.xml
- include:
file: db/changelog/eip/mysql/t201905/2019050901-dml-change-sbwName_and_sbwId-zerah.xml
再来看一下项目结构:
大概意思我想你应该可以看懂,就是引入了两个文件,这两个文件就称它是liquibase的配置脚本
文件命中的ddl和dml,应该不陌生吧
大概就是 数据库表结构的操作是ddl,数据增删改就是dml
7.配置脚本demo
2019050901-ddl-init-zerah.xml
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<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.6.xsd">
<!--eip表-->
<changeSet author="zerah" id="2019050901-staging-cn-south-1" context="staging-cn-south-1">
<preConditions>
<not>
<columnExists tableName="eip" columnName="sbw_id"></columnExists>
</not>
</preConditions>
<addColumn tableName="eip">
<column name="sbw_id" type="varchar(255)"/>
</addColumn>
<comment>eip表加入sbw_id字段</comment>
</changeSet>
<changeSet author="zerah" id="2019050901-staging-cn-north-3" context="staging-cn-north-3">
<preConditions>
<not>
<columnExists tableName="eip" columnName="sbw_id"></columnExists>
</not>
</preConditions>
<addColumn tableName="eip">
<column name="sbw_id" type="varchar(255)"/>
</addColumn>
<comment>eip表加入sbw_id字段</comment>
</changeSet>
</databaseChangeLog>
2019050901-dml-change-sbwName_and_sbwId-zerah.xml
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<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.6.xsd">
<!--EIP表数据迁移-->
<changeSet author="zerah" id="2019050903-staging-cn-south-1" context="staging-cn-south-1">
<sql>UPDATE eip eip1, eip eip2
SET eip1.sbw_id = eip2.shared_band_width_id where eip1.eip_id =eip2.eip_id;
</sql>
</changeSet>
<changeSet author="zerah" id="2019050903-staging-cn-north-3" context="staging-cn-north-3">
<sql>UPDATE eip eip1, eip eip2
SET eip1.sbw_id = eip2.shared_band_width_id where eip1.eip_id =eip2.eip_id;
</sql>
</changeSet>
</databaseChangeLog>
仔细看上面两个配置脚本中的context,我想应该大致明白context的作用了吧,就是以此来区分不同环境对不同changeset的引入
每个更改集都用 “id”属性和“author”属性唯一标识。“作者”属性可以最大限度地减少重复的可能性。
liquibase将每个更改集视为要应用于数据库的原子更改。通常最好只在更改集中包含一个更改
8. 总结
其实现在,启动项目,liquibase已经管理起来你对数据库的操作了,具体做的操作就是上面两个配置文件中配置的内容
检查你的数据库
你可以看到数据库现在额外创建了另外两个表:“databasechangelog”和“databasechangeloglock”。
- databasechangelog表包含已针对数据库运行的所有语句的列表。
- databasechangeloglock表用于确保两台计算机不会同时尝试修改数据库。
9.介绍
现在你已经糊里糊涂的在项目中整合上了liquibase,现在我们再来结合其他博客感受一下liquibase
首先来了解下liquibase是什么
Liquibase是一个用于跟踪、管理和应用数据库变化的开源的数据库重构工具。它将所有数据库的变化(包括结构和数据)都保存在XML文件中,便于版本控制
liquibase 可以干嘛?
- 不依赖于特定的数据库,目前支持包括Oracle/Sql Server/DB2/MySql/Sybase/PostgreSQL/Caché等12种数据库,这样在数据库的部署和升级环节可帮助应用系统支持多数据库。
- 提供数据库比较功能,比较结果保存在XML中,基于该XML你可用Liquibase轻松部署或升级数据库。
- 以XML存储数据库变化,其中以作者和ID唯一标识一个变化(ChangSet),支持数据库变化的合并,因此支持多开发人员同时工作。
- 在数据库中保存数据库修改历史(DatabaseChangeHistory),在数据库升级时自动跳过已应用的变化(ChangSet)。
- 提供变化应用的回滚功能,可按时间、数量或标签(tag)回滚已应用的变化。通过这种方式,开发人员可轻易的还原数据库在任何时间点的状态。
- 可生成数据库修改文档(HTML格式)
- 提供数据重构的独立的IDE和Eclipse插件。
传统的开发模式中的数据库修改之为什么使用liquibase
在日常的项目开发中,开发团队经常将数据库和应用程序视为单独的实体,这样就导致了数据库团队与应用开发团队分离造成团队之间信息交流不畅,信息交流不及时,这种情况通常表现为下面几种行为
手工变更数据库
不能与团队的其他成员分享数据库变更
使用不一致的方法变更数据库或数据
使用低效的手工方法管理数据库版本之间的变更
上面的几种行为都是我们在实际开发中遇到的问题,不仅效率低而且出错的机率也高,就算是老司机也会翻车
解决上面问题的思路是 减少人工手工变更数据库的机会,用程序管理数据库版本的更替
10.对现有数据库应用重构 & 常见的数据库操作
随着新特性添加到了应用程序中,经常需要变更数据库的结构或修改表约束。LiquiBase 提了超过 30 种数据库重构支持(参见 IBM参考资料)。本节将介绍 4 种重构:添加列(Add Column)、删除列(Drop Column)、创建表(Create Table)和操作数据。
1.添加列
在项目的开始,几乎不可能考虑到数据库中的所有列。而有时候,用户要求新的特性 —例如为存储在系统中的信息收集更多的数据 —这就要求添加新的列。
清单 4 使用 LiquiBase addColumn重构,向数据库中的 distributor表添加了一个列:
<changeSet id="4" author="joe">
<addColumn tableName="distributor">
<column name="phonenumber" type="varchar(255)"/>
</addColumn>
</changeSet>
2.删除列
假如在以后几个版本中,您想要删除在清单 4 添加的 phonenumber列。只需要调用 dropColumn重构,如清单 5 所示:
<dropColumn tableName="distributor" columnName="phonenumber"/>
3.创建表
向数据库添加一个新表也是常见的数据库重构。清单 6 创建了一个新表 distributor,定义了列、约束和默认值:
<changeSet id="3" author="betsey">
<createTable tableName="distributor">
<column name="id" type="int">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="name" type="varchar(255)">
<constraints nullable="false"/>
</column>
<column name="address" type="varchar(255)">
<constraints nullable="true"/>
</column>
<column name="active" type="boolean" defaultValue="1"/>
</createTable>
</changeSet>
4.操作数据
在应用了结构性数据重构后(例如添加列和创建表),通常需要向受重构影响的表中插入数据。此外,可能需要修改查找表(或其他类型的表)中的现有数据。清单 7 展示了如何使用一个 LiquiBase 变更集插入数据:
<changeSet id="3" author="betsey">
<code type="section" width="100%">
<insert tableName="distributor">
<column name="id" valueNumeric="3"/>
<column name="name" value="Manassas Beer Company"/>
</insert>
<insert tableName="distributor">
<column name="id" valueNumeric="4"/>
<column name="name" value="Harrisonburg Beer Distributors"/>
</insert>
</changeSet>
5.引入sql脚本
您应该编写用于操作数据的 SQL 脚本,因为使用 LiquiBase XML 变更集限制很多。有时候使用 SQL 脚本向数据库应用大量的变更会简单一些。LiquiBase 也可以支持这些情景。清单 8 调用变更集中的 insert-distributor-data.sql来插入 distributor表数据:
<changeSet id="6" author="joe">
<sqlFile path="insert-distributor-data.sql"/>
</changeSet>