java - Liquibase 支持多租户环境中的多个架构
问题描述
我正在开发一个多租户环境,该环境具有共享数据库和每个租户的独立架构。
我的租户表如下:
id|tenant_id|tenant_schema_name|company_flg|
--|---------|------------------|-----------|
还有一个 app_roles 表,计划在其中使用 liquibase 脚本本身播种一些数据。
app_roles 表如下:
role_id|role_nm |
-------|----------|
1|ROLE_ADMIN|
2|ROLE_USER |
为 defaultSchema(全局模式)中存在的所有租户运行 liquibase 脚本的 Bean 是:
@Bean
public MultiTenantSpringLiquibase liquibaseMt(DataSource dataSource)
throws SQLException {
MultiTenantSpringLiquibase multiTenantSpringLiquibase = new MultiTenantSpringLiquibase();
multiTenantSpringLiquibase.setDataSource(dataSource);
Statement stmt = null;
stmt = dataSource.getConnection().createStatement();
String sql = "SELECT tenant_schema_name FROM {defaultSchema}.tenant" ;
sql = sql.replace("{defaultSchema}", AllConstants.defaultSchema);
ResultSet rs = stmt
.executeQuery(sql);
List<String> schemas = new ArrayList<>();
while (rs.next()) {
String schemaName = rs.getString("tenant_schema_name");
logger.info(schemaName);
dataSource.getConnection().createStatement()
.executeUpdate("CREATE SCHEMA IF NOT EXISTS " + schemaName);
schemas.add(schemaName);
}
multiTenantSpringLiquibase.setSchemas(schemas);
multiTenantSpringLiquibase.setChangeLog(AllConstants.liquibasePath);
multiTenantSpringLiquibase.setShouldRun(true);
if(schemas.isEmpty()) {
multiTenantSpringLiquibase.setDefaultSchema(AllConstants.defaultSchema);
}
return multiTenantSpringLiquibase;
}
上面提到的 bean 为每个租户创建模式,并为租户的每个模式执行 liquibase。
下面是我的 liquibase 脚本:
db.changelog-master.yaml:
databaseChangeLog:
- include:
file: db/changelog/changes/db.changelog-create-v1.yml
- include:
file: db/changelog/changes/db.changelog-seed-v1.yml
db.changelog-create-v1.yml:
databaseChangeLog:
- changeSet:
id: author-create-3
author: author
preCondition:
onFail: MARK_RAN
not:
tableExists:
tableName: APP_ROLES
changes:
- createTable:
tableName: APP_ROLES
columns:
- column:
name: ROLE_ID
constraints:
primaryKey: true
nullable: false
primaryKeyName: APP_ROLE_PK
type: INTEGER
- column:
name: ROLE_NM
constraints:
nullable: false
type: VARCHAR(50)
- changeSet:
id: author-create-7
author: author
preConditions:
onFail: MARK_RAN
not:
sequenceExists:
sequenceName: TENANT_SEQ
changes:
- createSequence:
sequenceName: TENANT_SEQ
startValue: 1
minValue: 1
incrementBy: 1
- changeSet:
id: author-create-8
author: author
preCondition:
onFail: MARK_RAN
not:
tableExists:
tableName: TENANT
changes:
- createTable:
tableName: TENANT
columns:
- column:
name: ID
constraints:
primaryKey: true
nullable: false
primaryKeyName: TENANT_PK
type: INTEGER
- column:
name: TENANT_ID
type: VARCHAR(50)
- column:
name: TENANT_SCHEMA_NAME
type: VARCHAR(50)
- column:
name: COMPANY_FLG
type: BOOLEAN
db.changelog-seed-v1.yml:
databaseChangeLog:
- changeSet:
id: author-seed-1
author: author
preConditions:
onFail: MARK_RAN
sqlCheck:
expectedResult: 0
sql: select count(*) from app_roles;
changes:
- sql:
sql: INSERT INTO app_roles (role_id, role_nm) VALUES (1, 'ROLE_ADMIN');
INSERT INTO app_roles (role_id, role_nm) VALUES (2, 'ROLE_USER');
这里有问题的部分是创建脚本成功地为每个租户运行并为我创建了所需的表,但是种子脚本仅为默认模式和所有其他先决条件播种数据,它从默认模式中找到 2 行并绕过每个租户。
在这里,当应用程序第一次启动时,会创建默认模式(全局模式)。我在全局模式中使用 sql 查询创建租户并重新启动应用程序,以便为所有插入的 sql 租户运行 liquibase 脚本。
我如何以编程方式逻辑解决方案是以编程方式要求种子脚本针对特定模式运行,但我不知道该怎么做。
任何建议都会有很大帮助。
我已经参考了创建上述 bean的链接。
解决方案
推荐阅读
- assembly - 将 x86 代码转换为 x86-64 代码时有什么遗漏吗?
- python - 如何在仅包含 Numpy 数组的程序中使用 numba 的 jit?
- reactjs - 更改父组件的状态而不传递
- eclipse - 如何使用 Eclipse 和 Subversive SVN 管理非代码文件(文档等)?
- flutter - 从 Web API 获取数据的结果出现 FLUTTER 问题
- c# - 具有较少参数的 SqlTableAdapter.Insert()
- python - pandas 中的 df.iloc[:,1:2].values 和 df.iloc[:,1].values 有什么区别?
- java - 对象声明与实例化
- angular - Angular Universal npm run serve:universal 出现错误:ERROR ReferenceError: $ is not defined
- sql-server - 删除 SQL 数据库中的 crlf?