2025-02-09 21:02:47 +08:00

178 lines
4.6 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
description: 多租户(Tenant)
globs:
---
# 多租户v8.0新增)
多租户Multi-tenancy是一种软件架构模式允许单个应用实例服务多个租户客户组织。每个租户的数据是相互隔离的但共享同一个应用程序代码和基础设施。
## 主要特点
- **数据隔离**: 确保不同租户之间的数据严格分离,互不可见
- **资源共享**: 多个租户共享同一套应用程序代码和基础设施
- **独立配置**: 每个租户可以有自己的个性化配置和定制化需求
- **成本优化**: 通过资源共享降低运营和维护成本
## 实现
### 1、数据隔离
多租户的数据隔离有许多种方案但最为常见的是以列进行隔离的方式。Cool Admin 通过在`BaseEntity`中加入指定的列租户ID `tenantId`)对数据进行隔离。
::: tip 小贴士
v8.0之后,`BaseEntity`已经从`cool-midway/core`中移动至`src/modules/base/entity/base.ts`,方便开发者扩展定制
:::
`src/modules/base/entity/base.ts`
```ts
import {
Index,
UpdateDateColumn,
CreateDateColumn,
PrimaryGeneratedColumn,
Column,
} from 'typeorm';
import { CoolBaseEntity } from '@cool-midway/core';
/**
* 实体基类
*/
export abstract class BaseEntity extends CoolBaseEntity {
// 默认自增
@PrimaryGeneratedColumn('increment', {
comment: 'ID',
})
id: number;
@Index()
@CreateDateColumn({ comment: '创建时间' })
createTime: Date;
@Index()
@UpdateDateColumn({ comment: '更新时间' })
updateTime: Date;
@Index()
@Column({ comment: '租户ID', nullable: true })
tenantId: number;
}
```
### 2、条件注入
Cool 改造了 `typeorm`的 `Subscriber`,新增了以下四种监听:
```ts
/**
* 当进行select的QueryBuilder构建之后触发
*/
afterSelectQueryBuilder?(queryBuilder: SelectQueryBuilder<any>): void;
/**
* 当进行insert的QueryBuilder构建之后触发
*/
afterInsertQueryBuilder?(queryBuilder: InsertQueryBuilder<any>): void;
/**
* 当进行update的QueryBuilder构建之后触发
*/
afterUpdateQueryBuilder?(queryBuilder: UpdateQueryBuilder<any>): void;
/**
* 当进行delete的QueryBuilder构建之后触发
*/
afterDeleteQueryBuilder?(queryBuilder: DeleteQueryBuilder<any>): void;
```
在`src/modules/base/db/tenant.ts`中,通过`tenantId`进行条件注入,从而实现数据隔离。
## 使用
### 1、开启多租户
框架默认关闭多租户,需要手动开启,在`src/config/config.default.ts`中开启多租户
```ts
cool: {
// 是否开启多租户
tenant: {
// 是否开启多租户
enable: true,
// 需要过滤多租户的url 支持通配符,如/admin/**/* 表示admin模块下的所有接口都进行多租户过滤
urls: [],
},
}
```
tenant
### 2、代码中使用
只要开启了多租户,并配置了`urls`,那么框架会自动注入`tenantId`,开发者原本的代码不需要做任何修改,框架会自动进行数据隔离。
#### Controller
@CoolController的`add`、`delete`、`update`、`info`、`list`、`page`方法都支持过滤多租户。
#### Service
`Service`中使用多租户,以下是一个完整的示例,包含有效和无效的情况,开发者需要结合实际业务进行选择。
```ts
import { Inject, Provide } from '@midwayjs/core';
import { BaseService } from '@cool-midway/core';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository } from 'typeorm';
import { DemoGoodsEntity } from '../entity/goods';
import { UserInfoEntity } from '../../user/entity/info';
import { noTenant } from '../../base/db/tenant';
/**
* 商品服务
*/
@Provide()
export class DemoTenantService extends BaseService {
@InjectEntityModel(DemoGoodsEntity)
demoGoodsEntity: Repository<DemoGoodsEntity>;
@Inject()
ctx;
/**
* 使用多租户
*/
async use() {
await this.demoGoodsEntity.createQueryBuilder().getMany();
await this.demoGoodsEntity.find();
}
/**
* 不使用多租户(局部不使用)
*/
async noUse() {
// 过滤多租户
await this.demoGoodsEntity.createQueryBuilder().getMany();
// 被noTenant包裹不会过滤多租户
await noTenant(this.ctx, async () => {
return await this.demoGoodsEntity.createQueryBuilder().getMany();
});
// 过滤多租户
await this.demoGoodsEntity.find();
}
/**
* 无效多租户
*/
async invalid() {
// 自定义sql不进行多租户过滤
await this.nativeQuery('select * from demo_goods');
// 自定义分页sql进行多租户过滤
await this.sqlRenderPage('select * from demo_goods', {});
}
}
```