返回总目录


本篇目录

什么是多租户###

维基百科:“软件多租户是指一种软件架构,在这种软件架构中,软件的一个实例运行在服务器上并且为多个租户服务”。一个租户是一组共享该软件实例特定权限的用户。有了多租户架构,软件应用被设计成为每个租户提供一个 专用的实例包括该实例的数据的共享,还可以共享配置,用户管理,租户自己的功能和非功能属性。多租户和多实例架构相比,多租户分离了代表不同的租户操作的多个实例。

多租户用于创建Saas(Software as-a service)应用(云处理)。有几种类型的多租户:

多部署-多数据库

这实际上不是多租户。但是,如果我们为每个具有分开数据库的客户(租户)运行该应用的一个实例,那么我们可以在单个服务器上为多个租户提供服务。我们可以确定该应用的多个实例在相同的服务器环境不会相互冲突

这个对于一个不是为多租户设计的已存在应用也是可能的。创建这么一个应用更容易,因为该应用不需要了解多租户。但这种方式存在安装,使用和维护问题。

单部署-多数据库

在这种情况下,我们可以在一个服务器上运行应用的单个实例。对于每个登录用户,我们从master database中检测该用户的租户,并获得该租户的数据库信息(连接字符串)。然后我们可以将连接字符串存储到像session一样的变量中,同时,使用这个租户特定的连接字符串执行所有的数据库操作。

某种程度上,这样的应用应该设计成多租户。但是大多数的应用都独立于多租户。这种方式也存在一些安装,使用和维护问题。我们应该为每个租户创建并维护一个分离的数据库

单部署-单数据库

这是最真实的多租户架构:我们只将具有单个数据库应用的单个实例部署到单个服务器上。在(RDBMS)每个表中,都存在一个TenantId(或相似)字段,该字段用于分离每个租户之间的数据。

这种方法安装和维护都很简单,但唯独创建这么一个应用很难,因为我们必须要阻止一个租户读取或写入其他租户的数据。我们可以为每个数据库的读取(select)操作添加一个TenantId过滤器。而且,我们可以在每次写入的时候检查一下该实体是否和当前的租户相关。这是乏味而易于出错的,但ABP通过使用自动的数据过滤帮助我们处理这个事情。

如果我们有很多具有大量数据的租户,那么这种方法可能会有性能问题。我们可以使用关系型数据库的表分割特征或者将租户按组分到不同的服务器上。

ABP中的多租户###

ABP提供了创建单部署,单数据库,多租户架构的基础设施。

开启多租户

多租户默认是关闭的。我们可以在模块的PreInitialize方法中开启,如下所示:

Configuration.MultiTenancy.IsEnabled = true;

租主vs租户

首先,我们应该定义多租户系统中的两个条目:

  • 租主(Host):租主是单例的(只有一个租主)。租主会对创建和管理租户负责。因此,一个“租主用户”比所有的租户等级更高,并独立于所有租户,同时还能控制他们。
  • 租户(Tenant):租主的一个客户,具有自己的用户角色,权限,设置等。每个租户都可以完全独立于其他租户使用应用。一个多租户应用会有一个或多个租户。如果是一个CRM应用,那么不同的租户也有它们自己的账户,契约,产品和订单。因此,当我们说“**租户用户”的时候,意思就是一个租户拥有的用户。

Session

ABP定义了一个获取当前用户租户id的IAbpSession接口。该接口用于多租户获取当前的租户id。因此,它可以基于当前的租户id过滤数据。ABP中有以下规则:

  • 如果UserId和TenantId都是null,那么当前的用户没有登录到系统。因此,我们可以不知道当前用户是否是一个租主用户还是一个租户用户。在这种情况下,用户不能访问授权的内容。
  • 如果UserId不是null,TenantId是null,那么当前用户是一个租主用户。
  • 如果UserId不是null,TenantId也不是null,那么当前用户是租户用户。

更多关于session的信息请看后面的Session一节。

数据过滤器

当从数据库中检索实体时,我们必须添加一个TenantId过滤器来只获得当前的租户实体。当你为实体实现了IMustHaveTenant和IMayHaveTenant两个接口之一时,ABP会自动地完成数据过滤。

IMustHaveTenant接口

该接口通过定义TenantId属性来区分不同租户的实体。一个实现了IMustHaveTenant的实体例子如下:

public class Product : Entity, IMustHaveTenant
{
public int TenantId { get; set; } public string Name { get; set; } //...其他属性
}

这样,ABP知道这是一个特定租户的实体,并且会自动地将一个租户的实体从其他实体中分离出来。

IMayHaveTenant接口

我们可能需要在租户和租户之间共享一个实体类型。因此,一个实体可能会被一个租户或租主拥有。IMayHaveTenant接口也定义了TenantId(类似于IMustHaveTenant),但在这种情况下是nullable。实现了IMayHaveTenant的一个实体例子:

public class Role : Entity, IMayHaveTenant
{
public int? TenantId { get; set; } public string RoleName { get; set; } //...其他属性
}

我们可能会使用相同的Role类来存储租主角色和租户角色。这种情况下,TenantId表明这是一个租户实体还是一个租主实体。null值表示这是一个租主实体,非null值表示这被一个租户拥有,该租户的Id是TenantId

IMayHaveTenant不像IMustHaveTenant一样常用。比如,一个Product类可以不实现IMayHaveTenant接口,因为Product和实际的应用功能相关,和管理租户不相干。因此,要小心使用IMayHaveTenant接口,因为它更难维护租户和租主共享的代码。

保存实体

一个租户用户不应该创建或编辑其他租户的实体。如果相关的数据过滤器开启了,那么ABP会检查该实体相对于数据库的改变。

想要获得更多关于数据过滤器的信息,请看后面关于数据过滤器的博客。

ABP理论学习之多租户的更多相关文章

  1. ABP理论学习之Javascript API(理论完结篇)

    返回总目录 本篇目录 Ajax Notification Message UI block和busy 事件总线 Logging 其他工具功能 说在前面的话 不知不觉,我们送走了2015,同时迎来了20 ...

  2. 详解ABP框架的多租户

    (此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:ABP框架对多租户场景提供了很好的支持,内建了多租户的处理机制,今天我们来深入解析一下 ...

  3. ABP理论学习之开篇介绍

    返回总目录 为了和2016年春节赛跑,完成该系列博客,我牺牲了今天中午的时间来完成该系列的第一篇----开篇介绍.开篇介绍嘛,读过大学教材的同学都知道,这玩意总是那么无聊,跟考试没关系,干脆直接跳过, ...

  4. ABP理论学习之Abp Session

    返回总目录 本篇目录 介绍 注入Session 使用Session属性 介绍 当应用程序要求用户登录时,那么应用程序也需要知道当前用户正在执行的操作.虽然ASP.NET本身在展现层提供了Session ...

  5. ABP理论学习之设置管理

    返回总目录 本篇目录 介绍 定义设置 获取设置值 更改设置 关于缓存 介绍 每个应用程序都需要存储一些设置信息,然后在应用程序中的某个地方使用这些设置.ABP提供了健壮的基础设施来存储或检索服务端和客 ...

  6. ABP理论学习之数据过滤器

    返回总目录 本篇目录 介绍 预定义过滤器 关闭过滤器 开启过滤器 设置过滤器参数 定义自定义过滤器 其他ORM 介绍 软删除模式通常用于不会真正从数据库删除一个实体而是仅仅将它标记为"已删除 ...

  7. ABP理论学习之授权(Authorization)

    返回总目录 本篇目录 介绍 定义权限 检查权限 使用AbpAuthorize特性 使用IPermissionChecker Razor视图 客户端(Javascript) 权限管理者 介绍 几乎所有的 ...

  8. ABP理论学习之功能管理

    返回总目录 本篇目录 介绍 功能类型 定义功能 检查功能 功能管理者 版本说明 介绍 大多数的Saas(多租户)应用都有不同 功能的 版本(包).因此,他们可以给租户(客户)提供不同的 价格和功能选项 ...

  9. ABP理论学习之审计日志

    返回总目录 本篇目录 介绍 配置 通过特性开启/关闭 注意 我项目中的例子 介绍 维基百科说: "审计跟踪(也叫审计日志)是与安全相关的按照时间顺序的记录,记录集或者记录源,它们提供了活动序 ...

随机推荐

  1. (4)WebApi 跨域问题

    在做Web开发中,常常会遇到跨域的问题,到目前为止,已经有非常多的跨域解决方案. 通过自己的研究以及在网上看了一些大神的博客,写了一个Demo 首先新建一个webapi的程序,如下图所示: 由于微软已 ...

  2. byte[] 转十进制

    short s = 0; //一个16位整形变量,初值为 0000 0000 0000 0000 byte b1 = 1; //一个byte的变量,作为转换后的高8位,假设初值为 0000 0001 ...

  3. 【leetcode】Median of Two Sorted Arrays

    题目简述: There are two sorted arrays A and B of size m and n respectively. Find the median of the two s ...

  4. xamarin(3.9.236)里DATETIMENOW的错误。

    [ERROR] FATAL UNHANDLED EXCEPTION: System.EntryPointNotFoundException: monodroid_get_system_property ...

  5. iOS---FMDB数据升级

    本人在这里重要强调一下!!! 看这里,看这里,看这里,重要的事说三遍. 本人在项目开发中,由于需求问题,不得不对已经建立好的数据库进行修改(添加字段),我就很随意的直接添加了对一个的字段,运行一下,数 ...

  6. 【powerdesigner】将pdm或者cdm保存为普通图片格式

    1.首先全选或者选择你要保存的元素[Ctrl+A] 2.Edit---->Export  Image

  7. 白银5kg

    领悟: 1.其实大势涨也好,跌也好,如果我们知道价格到哪里会受阻或反弹,能出有出利润的空间,我们就可以做单.

  8. Java EE之servlet实现用户登录

    1.在连接数据库的JAVA类中添加查询功能: 在这之前有一个连接数据库的方法: Connection conn=null; PreparedStatement stat=null;           ...

  9. wpf 仿QQ图片查看器

    参考博客 WPF下的仿QQ图片查看器 wpf图片查看器,支持鼠标滚动缩放拖拽 实现效果 主要参考的WPF下的仿QQ图片查看器,原博主只给出了部分代码. 没有完成的部分 1.右下角缩略图是原图不是缩略图 ...

  10. org.openqa.selenium.remote.SessionNotFoundException: Unexpected error launch IE

    1.在启动ie浏览器前先加入属性设置一项: DesiredCapabilities ie = DesiredCapabilities.internetExplorer(); ie.setCapabil ...