多租户系统数据库怎么设计,共享表、独立 schema 还是独立库?
学完这篇,你将彻底搞懂多租户系统的三种主流数据库架构(共享表、独立 schema、独立库),掌握各自的优缺点,并能根据业务场景写出对应的 SQL 查询代码。
第一步:评估数据量与隔离需求
这一步要确定你的系统大概有多少个租户(用户),以及数据量级有多大,从而决定采用哪种方案。
- 查看业务规模:打开你的业务规划文档或统计后台,确认预计的租户数量。如果租户少于 100 个,且单个租户的数据量小于 1GB,通常建议使用共享表模式;如果租户在 100 到 1000 之间,且对数据安全要求较高,建议独立 Schema;如果租户超过 1000 个,或者需要极致的物理隔离,必须使用独立库模式。
- 明确隔离需求:确认是否需要不同租户的数据完全不可见。如果只是简单的逻辑隔离,共享表即可;如果涉及到严格的权限控制,必须选择 Schema 或库级隔离。
第二步:设计共享表模式(单库单表)
这一步要在一个数据库中创建所有租户的表,通过添加租户 ID 字段来区分数据,成本最低。
- 执行建表 SQL:在 Navicat 或 MySQL Workbench 等数据库工具中,执行以下 SQL 命令创建用户表,其中
tenant_id是核心字段。
CREATE TABLE `user_info` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`tenant_id` int(11) NOT NULL COMMENT '租户ID',
`username` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户信息表(共享表模式)';
- 配置主键生成策略:在 MyBatis 或 Hibernate 等框架的配置文件中,设置主键生成策略为
UUID或雪花算法,避免不同租户插入数据时出现主键冲突。
界面操作路径*:打开 application.yml 配置文件 → 找到 mybatis-plus.global-config.db-config 节点 → 修改 id-type 为 ASSIGN_UUID。
第三步:设计独立 Schema 模式(单库多 Schema)
这一步要在一个数据库服务器内创建多个独立的数据库(Schema),每个租户拥有独立的数据库空间,管理难度适中。
- 执行 Schema 创建 SQL:在数据库管理工具中,为每个租户执行创建数据库的命令。假设租户 A 的 ID 为 1,则创建名为
tenant_1的数据库。
CREATE DATABASE `tenant_1` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
- 执行建表 SQL:切换到
tenant_1数据库,在其中创建该租户专属的表结构,表名可以与共享表保持一致,但数据完全物理隔离。
USE `tenant_1`;
CREATE TABLE `user_info` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`username` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
第四步:设计独立库模式(多库)
这一步要为每个租户创建一个独立的数据库实例,隔离性最强,但资源消耗最大。
- 执行数据库创建命令:在数据库服务器上,为不同的租户创建独立的数据库实例。例如,租户 A 使用
db_tenant_a,租户 B 使用db_tenant_b。
CREATE DATABASE `db_tenant_a` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
- 配置连接池:在应用程序的配置文件中,配置支持动态数据源的路由机制。确保系统在执行 SQL 时,能根据租户 ID 自动切换到对应的数据库连接。
第五步:代码实现与查询示例
这一步要编写代码,根据不同的模式实现数据查询功能。
- 共享表模式查询:编写 DAO 层代码,在 SQL 语句中自动拼接
WHERE tenant_id = ?条件。
// 伪代码示例
String sql = "SELECT * FROM user_info WHERE tenant_id = " + currentTenantId;
List<User> users = jdbcTemplate.query(sql, rowMapper);
- 独立 Schema 模式查询:编写代码,根据租户 ID 动态切换
DataSource。
// 伪代码示例
DataSource targetDataSource = dataSourceMap.get(tenantId);
jdbcTemplate.setDataSource(targetDataSource);
String sql = "SELECT * FROM user_info";
List<User> users = jdbcTemplate.query(sql, rowMapper);
注意:在共享表模式下,如果使用自增主键,不同租户可能会产生 ID 冲突,务必使用雪花算法或 UUID。在独立库模式下,跨租户的事务处理非常复杂,通常建议限制在单租户事务范围内。
小结
- 共享表模式:适合租户少、数据量小的场景,成本低,但扩展性差,性能受限于单库容量。
- 独立 Schema 模式:适合中等规模租户,提供了较好的逻辑隔离,管理成本比独立库低。
- 独立库模式:适合大规模租户或对数据安全要求极高的场景,物理隔离最强,但维护成本和资源消耗最高。
- 核心设计点:无论哪种模式,
tenant_id都是识别数据归属的关键字段,必须在所有查询中显式传递。
本文转载自 GJ站长论坛,原文地址:https://www.gj0.com/thread-2706.html
转载请注明出处,版权归原作者所有。
转载请注明出处,版权归原作者所有。
全部回复 0
还没有回复,来抢沙发~