VonaJS多租户同时支持共享模式和独立模式

多实例/多租户

VonaJS 通过多实例的概念来支持多租户 SAAS 系统的开发。只需启动一个后端服务,即可支持多个实例同时运行

VonaJS 支持以下几种多实例/多租户模式:

  1. 共享模式:多个实例共享同一个数据库,通过实例Id字段隔离多实例之间的数据
  2. 独立模式:每个实例都使用独立的数据库,从而满足大数据量的业务需求
  3. 混合模式:在一个系统中同时支持共享模式独立模式,从而可以精确指定某个实例使用共享数据库还是独立数据库

实例配置

1. 测试环境、开发环境

在测试环境和开发环境中,系统默认提供了一个缺省实例。同时提供了两个测试实例,用于演示如何使用共享模式独立模式

src/backend/config/config/config.test.ts

src/backend/config/config/config.dev.ts

typescript 复制代码
// instances
config.instances = [
  { name: '', password: '', title: '', config: {} },
  { name: 'shareTest', password: '', title: '' },
  { name: 'isolateTest', password: '', title: '', id: 1000, isolate: true, isolateClient: 'isolateTest' },
];
  • 实例清单
名称 说明
empty 缺省实例
shareTest 用于演示共享模式,具体而言,shareTestempty共享同一个数据库
isolateTest 用于演示独立模式,具体而言,isolateTest使用独立的数据库
  • 实例属性
名称 说明
name 实例名
password 实例中用户admin的初始密码,默认是123456
title 网站标题
config 实例的配置信息
id 当使用独立模式时,必须明确指定唯一的实例Id
isolate 是否使用独立模式,默认为共享模式
isolateClient 当使用独立模式时,必须明确指定数据源

2. 生产环境

在生产环境,需要自行配置实例信息

src/backend/config/config/config.prod.ts

typescript 复制代码
config.instances = [
  { name: '', password: '', title: '', config: {} },
  { name: 'vona', password: '', title: '', config: {} },
];

如何添加新实例

下面以实例shareTest为例,演示如何添加新实例:

1. 添加类型定义

src/backend/config/config/config.ts

typescript 复制代码
declare module 'vona' {
  export interface IInstanceRecord {
    shareTest: never;
  }
}
  • 采用接口合并机制添加新实例的类型定义

2. 增加实例配置

在需要的 config 文件中添加实例配置,比如在测试环境配置新实例:

src/backend/config/config/config.test.ts

typescript 复制代码
// instances
config.instances = [
  { name: 'shareTest', password: '', title: '' },
];
  • 对于独立模式,还需要配置数据源,此处从略

获取当前实例名的规则

当用户访问后端 Api 时,后端会自动根据规则获取当前实例名,然后根据实例名获取实例信息

1. 模块配置

多实例是由模块 a-instance 提供的核心能力,可以在 App config 中修改模块的配置:

src/backend/config/config/config.prod.ts

typescript 复制代码
// modules
config.modules = {
  'a-instance': {
    getInstanceName: undefined,
    headerField: 'x-vona-instance-name',
    queryField: 'x-vona-instance-name',
  },
};
名称 说明
getInstanceName 提供自定义函数,用于获取当前实例名
headerField 从request header中获取当前实例名,header key默认为x-vona-instance-name
queryField 从request query中获取当前实例名,query key默认为x-vona-instance-name

2. 规则次序

系统按以下次序,依次判断当前实例名,当获取到实例名时则停止判断流程

  1. 如果提供了getInstanceName,则调用此函数
  2. 如果queryField不为空,则从 request query 中获取
  3. 如果headerField不为空,则从 request header 中获取
  4. 从域名中解析实例名

3. 如何从域名中解析实例名

比如,域名为https://cabloy.com,那么对应的实例名是cabloy。可以通过配置SERVER_SUBDOMAINOFFSET来修改计算规则

env/.env

typescript 复制代码
# server
SERVER_SUBDOMAINOFFSET = 1
  • SERVER_SUBDOMAINOFFSET = 1时,域名与实例名对应关系如下:
域名 实例名
cabloy.com cabloy
store.cabloy.com cabloy.store
  • SERVER_SUBDOMAINOFFSET = 2时,域名与实例名对应关系如下:
域名 实例名
cabloy.com 空字符串
store.cabloy.com store

使用多实例

1. 访问当前实例信息

typescript 复制代码
// 当前实例名
const name = this.ctx.instanceName;
// 当前实例对象
const instance = this.ctx.instance;
// 当前实例Id
const iid = this.ctx.instance.id;

2. 使用Model操作数据库

由于多实例的数据是相互隔离的,因此在操作数据库时,需要指定实例Id。VonaJS 提供了非常强大的Model对象,从而可以透明的处理多实例

typescript 复制代码
// create
await this.scope.model.student.insert({ name: 'Tom' });
// select
await this.scope.model.student.select();
// get
await this.scope.model.student.get({ id: 1 });
// update
await this.scope.model.student.update({ id: 1, name: 'Jimmy' });
// delete
await this.scope.model.student.delete({ id: 1 });

当我们使用 Model student操作数据时,系统会自动设置实例Id

3. 使用Query Builder操作数据库

如果使用builder()方法操作数据库,就需要自行添加实例Id

typescript 复制代码
await this.scope.model.student.builder().where({
  iid: this.ctx.instance.id,
  name: 'Tom',
});

如果使用builderSelect()方法操作数据库,系统会自动添加实例Id

typescript 复制代码
await this.scope.model.student.builderSelect().where({
  name: 'Tom',
});

4. 使用原生Sql操作数据库

如果使用原生Sql操作数据库,就需要自行添加实例Id

typescript 复制代码
await this.scope.model.student.query(
  'select * from demoStudent where iid=?',
  [this.ctx.instance.id],
);
await this.scope.model.student.queryOne(
  'select * from demoStudent where iid=? and id=?',
  [this.ctx.instance.id, 1],
);

Vona ORM已开源:https://github.com/vonajs/vona

相关推荐
2401_876221348 分钟前
数据库系统概论(第6版)模拟题2
数据库
爱学习的小可爱卢24 分钟前
数据库MySQL——MySQL 可重复读隔离级别:Read View 底层原理与幻读问题深度剖析(面试必知)
数据库·mysql
lifewange1 小时前
数据库索引里面的游标是什么?
数据库·oracle
咖啡の猫1 小时前
TypeScript 开发环境搭建
前端·javascript·typescript
PhDTool1 小时前
计算机化系统验证(CSV)的前世今生
数据库·安全·全文检索
banpu1 小时前
Spring相关
数据库·spring·sqlserver
老年DBA1 小时前
Ora2Pg 迁移Oracle至 PostgreSQL 之实战指南
数据库·postgresql·oracle
我是苏苏2 小时前
MSSQL04: SQLserver的用户权限管理
数据库
l1t2 小时前
达梦数据库和Oracle兼容性和性能比较
数据库·sql·oracle·达梦
離離原上譜2 小时前
Windows 环境下 Node.js + Claude Code 安装与配置教程
windows·node.js