设为首页 - 加入收藏
广告 1000x90
您的当前位置:主页 > 抖音运营 > 引流推广 > 正文

多租户数据库设计(怎么实现多租户id的使用)

来源:引流技巧 编辑:引流技巧 时间:2024-11-14

前言

什么是多租户

多租户技术(Multi-TenancyTechnology)又称多重租赁技术,简称SaaS,是一种软件架构技术,是实现如何在多用户环境下 (此处的多用户一般是面向企业用户)共用相同的系统或程序组件,并且可确保各用户间数据的隔离性。简单讲: 在一台服务器上运行单个应用实例,它为多个租户(客户)提供服务。从定义中我们可以理解:多租户是一种架 构,目的是为了让多用户环境下使用同一套程序,且保证用户间数据隔离。那么重点就很浅显易懂了,多租户的重 点就是同一套程序下实现多用户数据的隔离

隔离方案

目前基于多租户的数据库设计方案通常有如下三种:

  • 1、独立数据库 共享数据库

  • 2、独立 Schema 共享数据库

  • 3、共享数据库、共享数据表

独立数据库

即一个租户一个数据库。

优点

为不同的租户提供独立的数据库,用户数据隔离级别最高,安全性最好,有助于简化数据模型的扩展设计,满足不同租户的独特需求;如果出现故障,恢复数据比较简单。

缺点

数据库维护成本和购置成本的大大增加。

共享数据库,独立 Schema

即多个或所有租户共享Database,每个租户一个Schema。

什么是Schema

  • oracle数据库:在oracle中一个数据库可以具有多个用户,那么一个用户一般对应一个Schema,表都是建立在 Schema 中的,(可以简单的理解:在 oracle 中一个用户一套数据库表)

多租户数据库设计(怎么实现多租户id的使用)多租户数据库设计(怎么实现多租户id的使用)

  • mysql数据库:mysql数据中的schema比较特殊,并不是数据库的下一级,而是等同于数据库。比如执行 create schema test 和执行create database test效果是一模一样的

优点

为安全性要求较高的租户提供了一定程度的逻辑数据隔离,并不是完全隔离;每个数据库可以支持更多的租户数量。

缺点

如果出现故障,数据恢复比较困难,因为恢复数据库将牵扯到其他租户的数据;

如果需要跨租户统计数据,存在一定困难。 这种方案是方案一的变种。只需要安装一份数据库服务,通过不同的Schema对不同租户的数据进行隔离。由于数 据库服务是共享的,所以成本相对低廉。

共享数据库、共享数据表

即租户共享同一个Database、同一个Schema,但在表中通过tenant_id字段区分租户的数据,表明该记录是属于哪个租户的。这是共享程度最高、隔离级别最低的模式。

优点

所有租户使用同一套数据库,所以成本低廉。

缺点

隔离级别最低,安全性最低,需要在设计开发时加大对安全的开发量;这种方案和基于传统应用的数据库设计并没有任何区别,但是由于所有租户使用相同的数据库表,所以需要做好对 每个租户数据的隔离安全性处理,这就增加了系统设计和数据管理方面的复杂程度。 数据备份和恢复最困难,需要逐表逐条备份和还原。

如果希望以最少的服务器为最多的租户提供服务,并且租户接受以牺牲隔离级别换取降低成本,这种方案最适合。

集成

本文选择的是方案三!如果是自己从零开始进行开发,需要在每条 sql 上加上 tenant_id 条件。那开发成本特别大。但我们使用的是 Mybatis Plus,那就不需要如此复杂了,框架已经集成多租户使用。

创建表

CREATETABLE`test_tenant`(`id`int(11)unsignedNOTNULLAUTO_INCREMENT,`account`varchar(32)DEFAULTNULL,`email`varchar(64)DEFAULTNULL,`tenant_id`int(10)unsignedDEFAULTNULLCOMMENT'租户id',
PRIMARYKEY(`id`)
)ENGINE=InnoDBDEFAULTCHARSET=utf8;
复制代码

insert 语句

INSERTINTO`test`.`test_tenant`(`id`,`account`,`email`,`tenant_id`)VALUES(1,'cxyxj','cxyxj.qq.com',0);INSERTINTO`test`.`test_tenant`(`id`,`account`,`email`,`tenant_id`)VALUES(2,'awesome','awesome@163.com',1);INSERTINTO`test`.`test_tenant`(`id`,`account`,`email`,`tenant_id`)VALUES(3,'gongj','gongj@163.com',2);
复制代码

注意关键字段tenant_id。

搭建项目

依赖

搭建 Boot项目,加入以下依赖:

<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<mybatis-plus.version>3.5.0</mybatis-plus.version></properties><dependencies>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency></dependencies>复制代码

实体

@DatapublicclassTestTenant{@TableId(type=IdType.AUTO)privateIntegerid;privateStringaccount;privateStringemail;privateIntegertenantId;

}
复制代码

我们的主键类型为 int,所以需要修改主键策略,修改为自增,默认使用雪花算法生成全局唯一id,长度为19 位。

mapper接口

publicinterfaceTenantMapperextendsBaseMapper<TestTenant>{
}
复制代码

MybatisPlusConfig

importcom.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;importcom.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;importcom.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;importnet.sf.jsqlparser.expression.Expression;importnet.sf.jsqlparser.expression.LongValue;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importjava.util.List;@ConfigurationpublicclassMybatisPlusConfig{@Bean
publicMybatisPlusInterceptormybatisPlusInterceptor(){
MybatisPlusInterceptorinterceptor=newMybatisPlusInterceptor();
interceptor.addInnerInterceptor(newTenantLineInnerInterceptor(newTenantLineHandler(){@Override
publicExpressiongetTenantId(){//获得当前登录用户的租户id
returnnewLongValue(1111);
}
}));returninterceptor;
}
}
复制代码

在 Mybatis Plus 中,一切插件的主体是 InnerInterceptor。 目前已有的功能(***地址):

  • 自动分页: PaginationInnerInterceptor

  • 多租户: TenantLineInnerInterceptor

  • 动态表名: DynamicTableNameInnerInterceptor

  • 乐观锁: OptimisticLockerInnerInterceptor

  • sql 性能规范: IllegalSQLInnerInterceptor

  • 防止全表更新与删除: BlockAttackInnerInterceptor

本文使用到的是
TenantLineInnerInterceptor。在我们的代码中,使用了TenantLineInnerInterceptor 类的有参构造方法。入参为 TenantLineHandler对象。这是比较重要的对象,比如:某一些表不需要拼接多租户条件、多租户的字段名是什么。都是在这个对象中规定。

publicinterfaceTenantLineHandler{//获得租户ID值本文写死了111
ExpressiongetTenantId();//数据库字段默认为tenant_id
defaultStringgetTenantIdColumn(){return"tenant_id";
}//需要忽略拼接条件的表名
//方法默认返回false表示所有表都需要拼多租户条件
defaultbooleanignoreTable(StringtableName){returnfalse;
}//这个方法在之前版本是没有的!已给出租户列的insert不再拼接条件。使用用户给出的值。
//针对比较特殊的场景,比如:异步添加时,获取不到登录人的租户ID,则给默认租户ID
defaultbooleanignoreInsert(List<Column>columns,StringtenantIdColumn){returncolumns.stream().map(Column::getColumnName).anyMatch((i)->{returni.equalsIgnoreCase(tenantIdColumn);
});
}
}
复制代码

配置文件

server:
port:1998spring:
datasource:
url:jdbc:mysql:/127.0.0.1:3306/test?useSSL=false&useUnicode=true&characterEncoding=utf-8
username:root
password

微商引流技巧网 www.yinliujiqiao.com 联系QQ:1716014443 邮箱:1716014443@qq.com

Copyright © 2019-2024 强大传媒 网站地图 rss地图

Top