SpringBoot使⽤Liquibase最佳实践
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的算法不⼀样。
其它数据库规范不再赘述。
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns:xsi="/2001/XMLSchema-instance"
xmlns="/xml/ns/dbchangelog"
xsi:schemaLocation="/xml/ns/dbchangelog /xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<changeSet id="T100-20181009-001" author="markfredchen">
<createTable tableName="demo_user" remarks="⽤户表">
<column name="id" type="bigint" remarks="⽤户ID,主键">
<constraints nullable="false" primaryKey="true" primaryKeyName="pk_demo_user_id"/>
</column>
<column name="username" type="varchar(100)" remarks="⽤户名">
<constraints nullable="false"/>
</column>
...
</createTable>
</changeSet>
</databaseChangeLog>
有效⽂件管理
使⽤Liquibase中提供<include file="xxx"/>tag,可以将ChangeSet分布在不同⽂件中。同时<include/>⽀持多级引⽤。
基于此功能可以对项⽬中的ChangeSet进⾏有效管理。推荐使⽤以下规范进⾏管理。
根据发布进⾏管理
1. 每个发布新建⼀个⽂件夹,所有发布相关的ChangeSet⽂件以及数据初始化⽂件,均放在些⽂件夹中。
2. 每个发布新建⼀个l。此l中,include本次发布需要执⾏的ChangeSet⽂件
3. 根据开发⼩组独⽴ChangeSet⽂件(可选)
4. 根据功能独⽴ChangeSet⽂件。例如l, l
resources
|-liquibase
|-user
| |- l
| |- release.1.0.0
| | |- l
| | |- l -- ⽤户相关表ChangeSet
| | |- user.csv -- ⽤户初始化数据
| | |- l -- 公司相关表ChangeSet
| |- release.1.1.0
| | |- l
spring boot选择题| | |- ...
模块化管理
当项⽬变得庞⼤之后,⼀个服务可能包含的功能模块会越来越多。此时⼤家会想尽办法进⾏模块拆分,逐步进⾏微服务化。然⽽在⾯对错综复杂的Liquibase ChangeSet就会⽆从下⼿。针对这种将来可能会⾯对的问题,项⽬初期就对Liquibase进⾏模块化管理,将在未来带来很⼤收益。
⾸先说明⼀下Spring Boot中Liquibase默认是如何执⾏以及执⾏结果。
1. 在启动时,LiquibaseAutoConfiguration会根据默认配置初始化SpringLiquibase
2. SpringLiquibase.afterPropertiesSet()中执⾏ChangeSet⽂件
3. 第⼀次跑ChangeSets的时候,会在数据库中⾃动创建两个表databasechangelog和databasechangeloglock
因此我们可以认为⼀个SpringLiquibase执⾏为⼀个模块。
引⼊多模块管理时,基于上节⽂件管理规范,我们基于模块管理再做下调整。
resources
|-liquibase
|-user
| |- l
| |- release.1.0.0
| | |- l
| | |- l -- ⽤户相关表ChangeSet
| | |- user.csv -- ⽤户初始化数据
| | |- l -- 公司相关表ChangeSet
| |- release.1.1.0
| | |- l
| | |- ...
|- order
| |- l
| |- release.1.0.0
| | |- ...
当有⼀天我们需要把订单模块拆分成独⽴服务时,我们只需要将模块相关的ChangeSet⽂件迁出来。即可完成数据结构的拆分。
那如何在⼀个Spring Boot运⾏多个SpringLiquibase呢?需要对代码进⾏以下调整。
1. 禁⽤Spring Boot⾃动运⾏Liquibase。
当以下配置被启⽤时,Spring Boot AutoConfigure会使⽤默认配置初始化名为springLiquibase的Bean。然后我们不对其进⾏配置,Spring Boot启动时会报错。
# application.properties
# spring boot 2以上
abled=false
# spring boot 2以下
1. Spring Boot配置Liquibase Bean
配置两个SpringLiquibase Bean,Bean名称分别为userLiquibase和orderLiqubase。
@Configuration
public class LiquibaseConfiguration() {
/**
* ⽤户模块Liquibase
*/
@Bean
public SpringLiquibase userLiquibase(DataSource dataSource) {
SpringLiquibase liquibase = new SpringLiquibase();
// ⽤户模块Liquibase⽂件路径
liquibase.setChangeLog("classpath:liquibase/l");
liquibase.setDataSource(dataSource);
liquibase.setShouldRun(true);
liquibase.setResourceLoader(new DefaultResourceLoader());
// 覆盖Liquibase changelog表名
liquibase.setDatabaseChangeLogTable("user_changelog_table");
liquibase.setDatabaseChangeLogLockTable("user_changelog_lock_table");
return liquibase;
}
/**
* 订单模块Liquibase
*/
@Bean
public SpringLiquibase orderLiquibase() {
SpringLiquibase liquibase = new SpringLiquibase();
liquibase.setChangeLog("classpath:liquibase/l");
liquibase.setDataSource(dataSource);
liquibase.setShouldRun(true);
liquibase.setResourceLoader(new DefaultResourceLoader());
liquibase.setDatabaseChangeLogTable("order_changelog_table");
liquibase.setDatabaseChangeLogLockTable("order_changelog_lock_table");
return liquibase;
}
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论