摘要 :在SpringBoot
的默认单一数据源下,liquibase
能够进行数据库版本管理,如果是多租户情况下,则需要手动实现,本文主要介绍如何利用liquibase
来实现多租户场景下的数据库版本管理。
简介
本文介绍的多租户场景,是多个用户数据库,使用的是同一个服务实例,然后通过
header
传递的tenant-id
来区分具体使用哪一个数据库实例(如何实现多租户就不展开了,其他文章细说)。而数据库的版本管理,则需要统一进行管理,利用了SpringLiquibase
类提供的管理能力,Hikari
的数据库连接池。
配置说明
pom.xml
文件
xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
</dependency>
</dependencies>
resource
目录下的配置
mysql.xml
该文件配置数据库版本更新语句的目录
xml
<?xml version="1.0" encoding="UTF-8"?>
<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.1.xsd">
<!-- 初始化表结构 -->
<include file="/liquibase/mysql/*.sql"/>
</databaseChangeLog>
init.sql
sql
--liquibase formatted sql
--changeset nise:202311201420
CREATE TABLE `USER` (
`ID` bigint(20) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`ID`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='用户';
LiquibaseDataSourceProperties
属性配置类
arduino
@Data
public class LiquibaseDataSourceProperties {
/** 驱动名称 */
private String driverClassName;
/** 链接地址 */
private String jdbcUrl;
/** 用户名 */
private String username;
/** 密码 */
private String password;
/** 数据库schema */
private String schema;
}
schema
说明
也可以理解为数据库的隔离一种方式,只不过每一种数据库的表现形式不一样
mysql
:schema
和数据库的名称一样,同一个名称下只有一个库。oracle
:schema
就是数据库名称,oracle
一般采用服务名连接的。kingbase
:schema
是数据库里面的具体空间名称,比如public
,如果使用该方式实现多租户,则可以在同一个库里面通过命名空间区分。
LiquibaseService
管理服务,这里简单写一下,最好写到
try cache finally
中来关闭数据库连接,防止失败。
scss
@Service
public class LiquibaseService {
@Autowired
private ResourceLoader resourceLoader;
/**
* 初始化数据库
* @param properties
*/
public void init(LiquibaseDataSourceProperties properties) throws Exception{
HikariDataSource hikariDataSource = this.buildDataSource(properties);
SpringLiquibase liquibase = new SpringLiquibase();
liquibase.setDataSource(hikariDataSource);
liquibase.setResourceLoader(resourceLoader);
//指定changelog的位置,这里使用的一个master文件引用其他文件的方式
liquibase.setChangeLog("classpath*:liquibase/mysql.xml");
liquibase.setShouldRun(true);
liquibase.afterPropertiesSet();
hikariDataSource.close();
}
private HikariDataSource buildDataSource(LiquibaseDataSourceProperties properties){
HikariDataSource hikariDataSource = new HikariDataSource();
hikariDataSource.setDriverClassName(properties.getDriverClassName());
hikariDataSource.setJdbcUrl(properties.getJdbcUrl());
hikariDataSource.setUsername(properties.getUsername());
hikariDataSource.setPassword(properties.getPassword());
hikariDataSource.setSchema(properties.getSchema());
hikariDataSource.setMinimumIdle(1);
hikariDataSource.setMaximumPoolSize(1);
return hikariDataSource;
}
}
服务调用
一般采用的是多数据源方式,或者采用从缓存中读取多租户的配置信息,然后初始化数据库;下面我就手动调用来模拟实现。
less
@RestController
@RequestMapping(value = "liquibase")
public class LiquibaseController {
@Autowired
private LiquibaseService liquibaseService;
@PostMapping(value = "init")
public String init(@RequestBody LiquibaseDataSourceProperties properties) throws Exception{
liquibaseService.init(properties);
return "SUCCESS";
}
}
结果
最终会生成两张数据库管理表
DATABASECHANGELOG
、DATABASECHANGELOGLOCK
和自己的业务表