Sequelize 实现多租户系统的最佳实践
在产品设计和开发过程中,如果需要支持多用户或多租户(Multi-Tenant)服务,那么加强多租户的数据隔离是必不可少的。在 Node.js 后端开发中,Sequelize 是一款支持多种关系型数据库的 ORM 框架。在这篇文章中,我们将介绍如何使用 Sequelize 实现多租户系统的最佳实践,并讨论与开发者们分享一些省时省力的技巧和技能。
Sequelize 是一个优秀的 ORM 框架,允许用户使用面向对象的方式来操作各种不同的数据库,包括 MySQL、PostgreSQL、SQLite 和 MSSQL 等。Sequelize 不仅具有可靠的操作支持,而且拥有强大的数据验证、类型转换和数据库迁移能力等诸多优势。而为了实现多租户的数据隔离,首先我们需要确定多租户数据模型,之后我们将来详细介绍 Sequelize 实现多租户的方法。
多租户数据模型
在实现多租户系统时,有两个非常重要的模型:租户模型和租户隔离模型。一个租户代表着一个组织,可以细分为一个公司、一个部门或一个人。在这里,租户是一个抽象的概念,即您所服务的客户或者您的公司,因为每个租户都有一组独立的数据,需要被隔离和管理。
对于租户隔离模型来说,我们可以按照两种方式来分别实现多租户的隔离:数据库分别隔离和数据行(Row)分别隔离。前者意味着将不同租户的数据存储在不同的数据库中,每个租户拥有自己的数据库连接,它们之间没有共享任何数据;后者则意味着将所有租户的数据存储在同一个数据库中,但使用表中的行进行分隔。
首先介绍第一种方式,即数据库分别隔离模型的实现。
数据库分别隔离模型的实现
在使用 Sequelize 实现多租户的时候,最好的方式就是将所有租户的数据分别存储在自己的数据库中,即支持多个数据库连接。为了实现这种方式,我们需要现在 Sequelize 中配置多个数据库连接信息。接下来,我们要创建一个 Sequelize 实例,并使用 addDatabase
方法对每个租户创建独立的 Sequelize 实例。
-- -------------------- ---- ------- ----- --------- - --------------------- ----- ------ - -------------------- ----- -------------- - ----------------------- ----- --------- - --- ---------- ------------------------ ------------------------ ------------------------ - ----- -------------------- ----- -------------------- -------- ----------------------- -- -- ----- --------------- - ------------------------ ----- ------- - ----------------------------- ------------------------ -- - ---------------------- ------- --------------------------------- --------------------------------- --------------------------------- - ----- ----------------------------- ----- ----------------------------- -------- -------------------------------- -- -- ---
在以上代码中,我们首先导入了 Sequelize 和一个名为 config
的配置文件。我们将在配置文件中定义租户的数据库连接信息。之后,我们创建了一个名为 sequelize
的 Sequelize 实例,并使用 addDatabase
方法为每个租户创建了一个独立的数据库连接。
接下来,我们描述一下多租户的数据访问实现。我们需要在数据库中为每个租户创建自己的表和每个租户不同的数据。为此,我们需要一个中间件功能,用于连接到正确的数据库。这个中间件通常会在每次请求时调用,以避免对租户的请求使用错误的数据库连接。
-- -------------------- ---- ------- -------- ---------------------------- ---- ----- - ----- ------ - ------------------ -- ------- -- -------------------- - ------------- - --------------------------- ---------------------------- --------- -- - ---------------------- -- ------ ----------- -------- ------- -- ------------ -- - ------------------- -- ------- -- ------ ----------- -------- ---------------------------- -- ------- -- ------ ----------- --- - ---- - ---------------------------- --- -------- - -
在以上代码中,我们创建了一个中间件函数 connectToTenantDatabase
,它会获取当前用户请求的租户信息,如果存在租户,那么就连接到当前租户所在的数据库。如果连接成功,那么我们将保存当前数据库连接的 Sequelize 实例在 req.currentDb
属性中,并继续传递请求到下一个视图,否则,我们将返回一个状态码为 500 的错误信息。
数据行分别隔离模型的实现
在多租户的应用中,还有另外一种隔离租户数据的方式——数据行分别隔离。在这种模式下,多个租户的数据存储在同一个数据库表中,并且每个租户的数据是通过使用一个共有的字段来筛选的,常常是租户 ID。这种方式提供了更大的灵活性并且更容易实现,但也带来了一定的性能问题,因为它需要将租户 ID 添加到每个 SQL 查询中。
接下来,我们描述一下如何使用 Sequelize 实现数据行分别隔离的方式,方法类似于上面的数据库分别隔离一章。
和上面相同,我们需要导入 Sequelize
和 config
配置文件。在这种情况下,我们还需要定义一个我们的租户字段名称,我们称之为 tenantIdentifier
。
const Sequelize = require('sequelize'); const config = require('./config'); const tenantIdentifier = 'tenantId';
接下来,我们要实现 Sequelize 查询钩子,在查询数据库记录时,将该租户 ID 添加到 SQL 查询中。我们需要在 model 的定义中关闭 Sequelize 中的 timestamps 和 paranoid 选项,因为我们不想添加数据到每一行、也不想进行软删除。
-- -------------------- ---- ------- ----- ---- - ------------------------ - --------- ----------------- --------- ----------------- ------ ----------------- -- - ----------- ------ --------- ------ ------ - ----------- --------- -- - ----- ------------ - --------------------- ----- -------- - -------------------------------- -- ------- -------- --- ------------ - ----- --- --------- ------ ---------- -------- - -- ----------------------- - -------------------- - ----- - -- -------------- ---------- ------ - ---------------------------- -- - -- --------------------- - --- ---- - - -- - - ------------ - -- -- - -- -------- --- ----------------- - ----- --- ------------- ---------- ------- -------- - - - --- ------------------------------------- ----------- - ---- - ------------------------------- - --------- - ------ -------- -- ---------- --------- -- - ------------- - ------------- -- --------------------- ------ -------- -- -- ---
在以上代码中,我们定义了一个名为 User
的 Sequelize model,该 model 具有三个属性 username
、password
和 email
。此外,我们还定义了 beforeFind
和 afterFind
钩子,前者用于获取租户 tenantId
的值并添加其中,在查询记录后,该钩子则在响应中添加 count
属性。
总结
本文中,我们介绍了 Sequelize 实现多租户系统的最佳实践,并讨论了 Sequelize 在实现多租户数据隔离中可以使用的两种模型,即数据库分别隔离和数据行分别隔离。通过建模和中间件的支持,我们可以很容易地实现多租户的应用,并且隔离每个租户的数据,为用户提供一流的应用体验,同时实现不同租户的数据分别管理,提高系统性能,希望对您的应用开发过程有所帮助。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/64c9e31c5ad90b6d041879cd