前言
近期工作中有遇到多租户模式的应用场景,对此自己查阅了大量的资料。对可行性进行分析后选择了
共享库表,按租户id字段区分租户的方式去实现。以此记录一下方便日后所需查阅
1.熟悉多租户之前先来了解一下什么是SaaS系统
以下内容来着百度百科
SaaS平台是运营saas软件的平台。SaaS提供商为企业搭建信息化所需要的所有网络基础设施及软件、硬件运作平台,并负责所有前期的实施、后期的维护等一系列服务,企业无需购买软硬件、建设机房、招聘IT人员,即可通过互联网使用信息系统。SaaS 是一种软件布局模型,其应用专为网络交付而设计,便于用户通过互联网托管、部署及接入。
也就是说,我只需要能连接上互联网,并且给saas平台交租金,我就能用saas平台给我提供的系统服务。这方面最典型的例子就是各种云平台,例如阿里云。既然我能通过互联网使用saas平台提供的服务,那么其他人当然也是可以的。于是这就产生了一个多租户的问题。
2.什么是多租户模式
多租户,简单来说,是一种架构设计方式,就是在一台或者一组服务器上运行的saas系统,可以为多个租户(客户)提供服务,目的是为了让多个租户在互联网环境下使用同一套程序,且保证租户间的数据隔离。从这种架构设计的模式上,不难看出来,多租户架构的重点就是同一套程序下多个租户数据的隔离。由于租户数据是集中存储的,所以要实现数据的安全性,就是看能否实现对租户数据的隔离,防止租户数据不经意或被他人恶意地获取和篡改。
3.多租户数据隔离方式
目前saas多租户系统的数据隔离有三种解决方案,即:
- 为每个租户提供独立的数据库
- 独立的表空间
- 按字段区分租户
每种方案都有其各自的适用情况。
3.1.每个租户提供独立的数据库(或者说独立数据源)
这种方案的实现方式是所有租户共享同一个应用,但应用后端会连接多个数据库系统,一个租户单独使用一个数据库系统。这种方案的用户数据隔离级别最高,安全性最好,租户间的数据能够实现物理隔离。但成本较高。
如下图所示:

3.2.每个租户提供独立的表空间
这种方案的实现方式,就是所有租户共享同一个应用,应用后端只连接一个数据库系统,所有租户共享这个数据库系统,每个租户在数据库系统中拥有一个独立的表空间。表空间中的数据表结构都是一样的。DB2、ORACLE、PostgreSQL,一个数据库下可以有多个Schema(在mysql中其实就是分多个数据库)
如下图所示:

3.3.按租户id字段区分租户
这种方案是多租户方案中最简单的设计方式,即在每张表中都添加一个用于区分租户的字段(如租户id或租户代码)来标识每条数据属于哪个租户,其作用很像外键。当进行查询的时候每条语句都要添加该字段作为过滤条件,其特点是所有租户的数据全都存放在同一个表中,数据的隔离性是最低的,完全是通过字段来区分的。

3.4.三种数据隔离方案的优劣势分析
| 隔离方案 | 成本 | 支持租户数量 | 优点 | 不足 |
|---|---|---|---|---|
| 独立数据库系统 | 高 | 少 | 隔离级别最高,安全性最好,能够满足不同租户的独特需求,出现故障时恢复数据比较容易 | 数据库需要独立安装,维护成本和购置成本高 |
| 共享数据库,独立表空间 | 中 | 较多 | 提供了一定程度的逻辑数据隔离,一个数据库系统可支持多个租户 | 出现故障的情况下,数据恢复相对而言比较复杂 |
| 按租户id字段区分 | 低 | 非常多 | 维护和购置成本最低,每个数据库能够支持的租户数量最多 | 隔离级别最低,安全性也最低,数据备份和恢复非常复杂,需要逐表逐条备份和还原 |
4.使用Mybatisplus搭建多租户模式(方式三的实现:共享库表,按租户id字段区分租户)
4.1.MyBatisPlusConfig.java
package com.bitvalue.gp.sys.config;
import com.bitvalue.gp.sys.core.mybatis.dbid.GunsDatabaseIdProvider;
import com.bitvalue.gp.sys.core.mybatis.fieldfill.CustomMetaObjectHandler;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* MyBatisPlusConfig扩展插件配置
*
* @author tangling
* @date 2021/4/18 10:49
*/
@Configuration
//扫描mapper
@MapperScan(basePackages = {
"com.bitvalue.gp.**.mapper"})
public class MyBatisPlusConfig {
/**
* mp多租户配置
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 多租户插件
interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new CustomTenantLineHandler()));
// 分页插件(ps:如果项目中有用到分页插件可以添加如下这行代码,但是必须要写在多租户插件后面)
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}

本文介绍了一种在MyBatisPlus中实现多租户的方法,通过按租户ID字段区分租户的方式来实现数据隔离,适用于低成本、高租户数量的场景。
&spm=1001.2101.3001.5002&articleId=116646998&d=1&t=3&u=4b234b96631142f2b47bc9218f5783ff)
1万+

被折叠的 条评论
为什么被折叠?



