Liquibase 问题

随着项目的发展,一个项目中的代码量会非常庞大,同时数据库表也会错综复杂。如果一个项目使用了 Liquibase 对数据库结构进行管理,越来越多的问题会浮现出来。

  1. ChangeSet 文件同时多人在修改,自己的 ChangeSet 被改掉,甚至被删除掉。

  2. 开发人员将 ChangeSet 添加到已经执行过的文件中,导致执行顺序出问题。

  3. 开发人员擅自添加对业务数据的修改,其它环境无法执行并报错。

  4. ChangeSet 中 SQL 包含 schema 名称,导致其它环境 schema 名称变化时,ChangeSet 报错。

  5. 开发人员不小心改动了已经执行过的 ChangeSet,在启动时会报错。

Liquibase 基本规范

  1. ChangeSet id 使用 [任务 ID]-[日期]-[序号],如 T100-20181009-001

  2. ChangeSet 必须填写 author

  3. Liquibase 禁止对业务数据进行 sql 操作

  4. 使用<sql>时,禁止包含 schema 名称

  5. Liquibase 禁止使用存储过程

  6. 所有表,列要加 remarks 进行注释

  7. 已经执行过的 ChangeSet 严禁修改。

  8. 不要随便升级项目 liquibase 版本,特别是大版本升级。不同版本 ChangeSet MD5SUM 的算法不一样。

其它数据库规范不再赘述。

1.  <?xml version="1.0" encoding="UTF-8"?>

2.  <databaseChangeLog

3.  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

4.  xmlns="http://www.liquibase.org/xml/ns/dbchangelog"

5.  xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">

6.  <changeSet id="T100-20181009-001" author="markfredchen" >

7.  <createTable table>

8.  <column >

9.  <constraints nul/>

10.  </column>

11.  <column >

12.  <constraints nul/>

13.  </column>

14.  ...

15.  </createTable>

16.  </changeSet>

17.  </databaseChangeLog>

有效文件管理

使用 Liquibase 中提供<include file="xxx"/>tag,可以将 ChangeSet 分布在不同文件中。同时<include/>支持多级引用。基于此功能可以对项目中的 ChangeSet 进行有效管理。推荐使用以下规范进行管理。

根据发布进行管理

  1. 每个发布新建一个文件夹,所有发布相关的 ChangeSet 文件以及数据初始化文件,均放在些文件夹中。

  2. 每个发布新建一个 master.xml。此 master.xml 中,include 本次发布需要执行的 ChangeSet 文件

  3. 根据开发小组独立 ChangeSet 文件 (可选)

  4. 根据功能独立 ChangeSet 文件。例如 user.xml, company.xml

1.  `resources` 
2.  `|-liquibase` 
3.  `|-user` 
4.  `| |- master.xml` 
5.  `| |- release.1.0.0` 
6.  `| | |- release.xml` 
7.  `| | |- user.xml -- 用户相关表ChangeSet` 
8.  `| | |- user.csv -- 用户初始化数据` 
9.  `| | |- company.xml -- 公司相关表ChangeSet` 
10.  `| |- release.1.1.0` 
11.  `| | |- release.xml` 
12.  `| | |- ...`

模块化管理

当项目变得庞大之后,一个服务可能包含的功能模块会越来越多。此时大家会想尽办法进行模块拆分,逐步进行微服务化。然而在面对错综复杂的 Liquibase ChangeSet 就会无从下手。针对这种将来可能会面对的问题,项目初期就对 Liquibase 进行模块化管理,将在未来带来很大收益。首先说明一下 Spring Boot 中 Liquibase 默认是如何执行以及执行结果。

  1. 在启动时,LiquibaseAutoConfiguration 会根据默认配置初始化 SpringLiquibase

  2. SpringLiquibase.afterPropertiesSet() 中执行 ChangeSet 文件

  3. 第一次跑 ChangeSets 的时候,会在数据库中自动创建两个表databasechangelogdatabasechangeloglock

因此我们可以认为一个 SpringLiquibase 执行为一个模块。

引入多模块管理时,基于上节文件管理规范,我们基于模块管理再做下调整。

1.  `resources` 
2.  `|-liquibase` 
3.  `|-user` 
4.  `| |- master.xml` 
5.  `| |- release.1.0.0` 
6.  `| | |- release.xml` 
7.  `| | |- user.xml -- 用户相关表ChangeSet` 
8.  `| | |- user.csv -- 用户初始化数据` 
9.  `| | |- company.xml -- 公司相关表ChangeSet` 
10.  `| |- release.1.1.0` 
11.  `| | |- release.xml` 
12.  `| | |- ...` 
13.  `|- order` 
14.  `| |- master.xml` 
15.  `| |- release.1.0.0` 
16.  `| | |- ...`

当有一天我们需要把订单模块拆分成独立服务时,我们只需要将模块相关的 ChangeSet 文件迁出来。即可完成数据结构的拆分。

那如何在一个 Spring Boot 运行多个 SpringLiquibase 呢?需要对代码进行以下调整。

  1. 禁用 Spring Boot 自动运行 Liquibase。

当以下配置被启用时,Spring Boot AutoConfigure 会使用默认配置初始化名为 springLiquibase 的 Bean。然后我们不对其进行配置,Spring Boot 启动时会报错。

1.  `# application.properties` 
2.  `# spring boot 2以上` 
3.  `spring.liquibase.enabled=false` 
4.  `# spring boot 2以下` 
5.  `liquibase.enabled=false`
  1. Spring Boot 配置 Liquibase Bean

配置两个 SpringLiquibase Bean,Bean 名称分别为 userLiquibase 和 orderLiqubase。

1.  @Configuration

2.  public class LiquibaseConfiguration() {

4.  /**

5.  *  用户模块Liquibase

6.  */

7.  @Bean

8.  public SpringLiquibase userLiquibase(DataSource dataSource) {

9.  SpringLiquibase liquibase = new SpringLiquibase();

10.  // 用户模块Liquibase文件路径

11.  liquibase.setChangeLog("classpath:liquibase/user/master.xml");

12.  liquibase.setDataSource(dataSource);

13.  liquibase.setShouldRun(true);

14.  liquibase.setResourceLoader(new DefaultResourceLoader());

15.  // 覆盖Liquibase changelog表名

16.  liquibase.setDatabaseChangeLogTable("user_changelog_table");

17.  liquibase.setDatabaseChangeLogLockTable("user_changelog_lock_table");

18.  return liquibase;

19.  }

20.  /**

21.  *  订单模块Liquibase

22.  */

23.  @Bean

24.  public SpringLiquibase orderLiquibase() {

25.  SpringLiquibase liquibase = new SpringLiquibase();

26.  liquibase.setChangeLog("classpath:liquibase/order/master.xml");

27.  liquibase.setDataSource(dataSource);

28.  liquibase.setShouldRun(true);

29.  liquibase.setResourceLoader(new DefaultResourceLoader());

30.  liquibase.setDatabaseChangeLogTable("order_changelog_table");

31.  liquibase.setDatabaseChangeLogLockTable("order_changelog_lock_table");

32.  return liquibase;

33.  }

34.  }

来源链接:

https://www.bbsmax.com/A/VGzlKEQwdb/

c189bb2710d461736d55d0b16fc44a2d.png

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐