⭐ 推荐:社区规则条款 V1.0

多租户系统数据库怎么设计,共享表、独立 schema 还是独立库?

GJ
GJ 资深会员 👑黑卡会员
发布于 2026-11-02 10:09 ·2 浏览 ·0 回复

学完这篇,你将彻底搞懂多租户系统的三种主流数据库架构(共享表、独立 schema、独立库),掌握各自的优缺点,并能根据业务场景写出对应的 SQL 查询代码。

第一步:评估数据量与隔离需求

这一步要确定你的系统大概有多少个租户(用户),以及数据量级有多大,从而决定采用哪种方案。

  1. 查看业务规模:打开你的业务规划文档或统计后台,确认预计的租户数量。如果租户少于 100 个,且单个租户的数据量小于 1GB,通常建议使用共享表模式;如果租户在 100 到 1000 之间,且对数据安全要求较高,建议独立 Schema;如果租户超过 1000 个,或者需要极致的物理隔离,必须使用独立库模式。
  2. 明确隔离需求:确认是否需要不同租户的数据完全不可见。如果只是简单的逻辑隔离,共享表即可;如果涉及到严格的权限控制,必须选择 Schema 或库级隔离。

第二步:设计共享表模式(单库单表)

这一步要在一个数据库中创建所有租户的表,通过添加租户 ID 字段来区分数据,成本最低。

  1. 执行建表 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='用户信息表(共享表模式)';
    
  1. 配置主键生成策略:在 MyBatis 或 Hibernate 等框架的配置文件中,设置主键生成策略为 UUID 或 雪花算法,避免不同租户插入数据时出现主键冲突。
  2. 界面操作路径*:打开 application.yml 配置文件 → 找到 mybatis-plus.global-config.db-config 节点 → 修改 id-type 为 ASSIGN_UUID。

第三步:设计独立 Schema 模式(单库多 Schema)

这一步要在一个数据库服务器内创建多个独立的数据库(Schema),每个租户拥有独立的数据库空间,管理难度适中。

  1. 执行 Schema 创建 SQL:在数据库管理工具中,为每个租户执行创建数据库的命令。假设租户 A 的 ID 为 1,则创建名为 tenant_1 的数据库。
    CREATE DATABASE `tenant_1` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
    
  1. 执行建表 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;
    

第四步:设计独立库模式(多库)

这一步要为每个租户创建一个独立的数据库实例,隔离性最强,但资源消耗最大。

  1. 执行数据库创建命令:在数据库服务器上,为不同的租户创建独立的数据库实例。例如,租户 A 使用 db_tenant_a,租户 B 使用 db_tenant_b。
    CREATE DATABASE `db_tenant_a` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
    
  1. 配置连接池:在应用程序的配置文件中,配置支持动态数据源的路由机制。确保系统在执行 SQL 时,能根据租户 ID 自动切换到对应的数据库连接。

第五步:代码实现与查询示例

这一步要编写代码,根据不同的模式实现数据查询功能。

  1. 共享表模式查询:编写 DAO 层代码,在 SQL 语句中自动拼接 WHERE tenant_id = ? 条件。
    // 伪代码示例
    String sql = "SELECT * FROM user_info WHERE tenant_id = " + currentTenantId;
    List<User> users = jdbcTemplate.query(sql, rowMapper);
    
  1. 独立 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。在独立库模式下,跨租户的事务处理非常复杂,通常建议限制在单租户事务范围内。

小结

  1. 共享表模式:适合租户少、数据量小的场景,成本低,但扩展性差,性能受限于单库容量。
  2. 独立 Schema 模式:适合中等规模租户,提供了较好的逻辑隔离,管理成本比独立库低。
  3. 独立库模式:适合大规模租户或对数据安全要求极高的场景,物理隔离最强,但维护成本和资源消耗最高。
  4. 核心设计点:无论哪种模式,tenant_id 都是识别数据归属的关键字段,必须在所有查询中显式传递。
本文转载自 GJ站长论坛,原文地址:https://www.gj0.com/thread-2706.html
转载请注明出处,版权归原作者所有。
—/ 5暂无评分
还没有评分,来打第一分吧

全部回复 0

还没有回复,来抢沙发~