当前位置:首页 > 科技  > 软件

SpringBoot多租户三种架构实现方案详解

来源: 责编: 时间:2024-05-29 08:58:35 85观看
导读环境:SpringBoot3.3.01. 简介多租户表示应用程序的单个运行实例同时为多个客户机(租户)服务的体系结构。这在SaaS解决方案中非常常见。在这些系统中,隔离与各种租户相关的信息(数据、定制等)是一个特殊的挑战。这包括存储在

环境:SpringBoot3.3.0IQA28资讯网——每日最新资讯28at.com

1. 简介

多租户表示应用程序的单个运行实例同时为多个客户机(租户)服务的体系结构。这在SaaS解决方案中非常常见。在这些系统中,隔离与各种租户相关的信息(数据、定制等)是一个特殊的挑战。这包括存储在数据库中的每个租户拥有的数据。以下是三种常用的多租户架构实现方案:IQA28资讯网——每日最新资讯28at.com

1.1 独立数据库(Separate database)

图片图片IQA28资讯网——每日最新资讯28at.com

每个租户的数据都保存在一个物理上独立的数据库实例中。JDBC连接将专门指向每个数据库,因此任何池都将按租户进行。这里,一种通用的应用程序方法是为每个租户定义JDBC连接池,并根据与当前登录用户相关联的租户标识符来选择要使用的池。IQA28资讯网——每日最新资讯28at.com

优点:IQA28资讯网——每日最新资讯28at.com

  • 数据隔离级别高,安全性好
  • 可以根据租户的需求进行数据库优化和扩展
  • 备份和恢复操作相对简单

缺点:IQA28资讯网——每日最新资讯28at.com

  • 成本较高,需要为每个租户购买和维护独立的数据库实例
  • 可能存在硬件资源浪费,因为每个租户可能只使用了数据库的一部分功能

1.2 独立Schema(Separate schema)

图片IQA28资讯网——每日最新资讯28at.com

每个租户的数据都保存在单个数据库实例上的不同数据库Schema中。这里有两种不同的定义JDBC连接的方法:IQA28资讯网——每日最新资讯28at.com

  • 连接可以特定地指向每个Schema,就像单独的数据库方法中那样。这是一个选项,前提是驱动程序支持在连接URL中命名默认Schema,或者池机制支持命名用于其连接的Schema。使用这种方法,我们将为每个租户创建一个不同的JDBC连接池,使用的连接池将基于与当前登录用户相关联的“租户标识符”进行选择。
  • 连接可以指向数据库本身(使用某些默认Schema),但使用SQL SET schema(或类似的)命令可以更改连接。使用这种方法,我们将有一个JDBC连接池用于为所有租户提供服务,但在使用连接之前,它将被更改为引用由与当前登录用户关联的“租户标识符”命名的模式。

优点:IQA28资讯网——每日最新资讯28at.com

  • 降低了数据库成本,因为多个租户共享一个数据库实例
  • 数据隔离级别仍然较高,因为每个租户使用独立的模式

缺点:IQA28资讯网——每日最新资讯28at.com

  • 模式之间可能存在资源竞争和性能瓶颈
  • 备份和恢复操作可能更加复杂,因为需要针对每个模式进行单独操作

1.3 分区数据(Partitioned (discriminator) data)

图片IQA28资讯网——每日最新资讯28at.com

所有数据都保存在一个数据库Schema中。通过使用分区列对每个租户的数据进行分区。这种方法将使用单个连接池为所有租户提供服务。但是,在这种方法中,应用程序需要对每个SQL语句添加分区列(查询时where条件加入分区列作为查询条件)。IQA28资讯网——每日最新资讯28at.com

优点:IQA28资讯网——每日最新资讯28at.com

  • 成本最低,因为所有租户都共享同一个数据库实例和模式
  • 数据访问和查询效率可能较高,因为数据都在同一个表中

缺点:
IQA28资讯网——每日最新资讯28at.com

  • 数据隔离级别最低,可能存在安全风险
  • 需要通过应用程序逻辑来确保数据的正确隔离和访问控制
  • 数据备份和恢复操作可能非常复杂,因为需要考虑到所有租户的数据

接下来我会对分区数据独立数据库2种架构进行详细的介绍。独立Schema方案其实与独立数据库模式挺像的,如果基于MySQL其实对应的就是不同数据库(可以是同一个MySQL实例,通过use xxx切换数据库),基于Oracle就是对应不同的用户上(并非schema与用户等同)。IQA28资讯网——每日最新资讯28at.com

2. 实战案例

2.1 分区数据

注:请先确保你当前使用的SpringBoot版本(Spring Data JPA)整合的Hibernate版本至少是6.0版本以上。IQA28资讯网——每日最新资讯28at.com

实体定义

@Entity@Table(name = "t_person")public class Person {  @Id  @GeneratedValue(strategy = GenerationType.IDENTITY)  private Long id ;  private String name ;  private Integer age ;  @TenantId  private String tenantId ;}

这里通过@TenantId注解标注,该字段专门用来分区租户的,Hibernate在查询数据时会自动添加该查询条件,如果你使用的本地SQL(自己编写SQL),那么需要你自行添加该条件(租户ID条件)。IQA28资讯网——每日最新资讯28at.com

编写DAO&Service

// DAOpublic interface PersonRepository extends JpaRepository<Person, Long>, JpaSpecificationExecutor<Person> {}// Service@Servicepublic class PersonService {  private final PersonRepository personRepository ;  public PersonService(PersonRepository personRepository) {    this.personRepository = personRepository ;  }  // 查询所有Person数据  public List<Person> persons() {    return this.personRepository.findAll() ;  }}

Controller接口

@GetMapping("")public List<Person> persons() {  return this.personService.persons() ;}

以上是开发一个业务功能的基本操作,接下来才是重点IQA28资讯网——每日最新资讯28at.com

租户标识解析处理

该的作用获取当前租户ID,这里基于ThreadLocal实现IQA28资讯网——每日最新资讯28at.com

public class TenantIdResolver implements CurrentTenantIdentifierResolver<String> {  private static final ThreadLocal<String> CURRENT_TENANT = new ThreadLocal<>();  public void setCurrentTenant(String currentTenant) {    CURRENT_TENANT.set(currentTenant);  }  @Override  public String resolveCurrentTenantIdentifier() {    // 注意这里不能返回null    return Optional.ofNullable(CURRENT_TENANT.get()).orElse("default") ;  }  @Override  public boolean validateExistingCurrentSessions() {    return true;  }}

上面的组件用来从当前的ThreadLocal中获取租户ID,接下来就是像ThreadLocal存入租户ID。IQA28资讯网——每日最新资讯28at.com

Web拦截器

该拦截器的作用用来从请求Header中获取租户ID,存入ThreadLocal中。IQA28资讯网——每日最新资讯28at.com

@Componentpublic class TenantIdInterceptor implements HandlerInterceptor {  private final TenantIdResolver tenantIdResolver;  public TenantIdInterceptor(TenantIdResolver tenantIdResolver) {    this.tenantIdResolver = tenantIdResolver;  }  @Override  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {    String tenantId = request.getHeader("x-tenant-id");    tenantIdResolver.setCurrentTenant(tenantId);    return true ;  }}

最后一步就是配置hibernate,设置租户ID的解析器。IQA28资讯网——每日最新资讯28at.com

配置租户标识解析器

spring:  jpa:    properties:      hibernate:        '[tenant_identifier_resolver]': 'com.pack.tenant.config.TenantIdResolver'

完成以上类及配置的编写后就实现了基于列区分(分区)的多租户架构方案。IQA28资讯网——每日最新资讯28at.com

测试

准备数据:IQA28资讯网——每日最新资讯28at.com

图片图片IQA28资讯网——每日最新资讯28at.com

图片图片IQA28资讯网——每日最新资讯28at.com

图片图片IQA28资讯网——每日最新资讯28at.com

SQL执行情况:IQA28资讯网——每日最新资讯28at.com

图片图片IQA28资讯网——每日最新资讯28at.com

自动添加了tenant_id查询条件。IQA28资讯网——每日最新资讯28at.com

2.2 独立数据库

每租户对应一个数据库,这需要在项目中配置多个数据源,同时提供一个数据源路由的核心类。IQA28资讯网——每日最新资讯28at.com

定义多数据源配置

你也可以将数据源的信息专门存放在数据表中。IQA28资讯网——每日最新资讯28at.com

pack:  datasource:    defaultDs: ds1    config:      ds1:        driverClassName: com.mysql.cj.jdbc.Driver        url: jdbc:mysql://localhost:3306/tenant-01        username: tenant01        password: xxxooo        type: com.zaxxer.hikari.HikariDataSource      ds2:        driverClassName: com.mysql.cj.jdbc.Driver        url: jdbc:mysql://localhost:3306/tenant-02        username: tenant02        password: oooxxx        type: com.zaxxer.hikari.HikariDataSource

在Spring实现多数据源切换,可以通过继承AbstractRoutingDataSource。IQA28资讯网——每日最新资讯28at.com

public class PackRoutingDataSource extends AbstractRoutingDataSource {  @Override  protected Object determineCurrentLookupKey() {    return DataSourceContextHolder.get() ;  }}public class DataSourceContextHolder {  private static final ThreadLocal<String> HOLDER = new InheritableThreadLocal<>() ;  public static void set(String key) {    HOLDER.set(key) ;  }  public static String get() {    return HOLDER.get() ;  }  public static void clear() {    HOLDER.remove() ;   }}

配置数据源Bean

@Configurationpublic class DataSourceConfig {  @Bean  public DataSource dataSource(MultiDataSourceProperties properties) {    PackRoutingDataSource dataSource = new PackRoutingDataSource(properties.getDefaultDs()) ;    Map<Object, Object> targetDataSources = new HashMap<>() ;    // PackDataSourceProperties类仅仅就是继承DataSourceProperties    Map<String, PackDataSourceProperties> configs = properties.getConfig() ;    configs.forEach((key, props) -> {      targetDataSources.put(key, createDataSource(props, HikariDataSource.class)) ;    });    dataSource.setTargetDataSources(targetDataSources) ;    return dataSource ;  }  private static <T> T createDataSource(PackDataSourceProperties properties, Class<? extends DataSource> type) {    // 这里没有考虑池的配置    return (T) properties.initializeDataSourceBuilder().type(type).build();  }}

接下来定义拦截器,设置当前要操作的数据源。IQA28资讯网——每日最新资讯28at.com

Web拦截器

@Componentpublic class TenantIdInterceptor implements HandlerInterceptor {  @Override  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {    String tenantId = request.getHeader("x-tenant-id");    DataSourceContextHolder.set(tenantId) ;    return true ;  }}

以上就完成了多数据源的所有类及配置的编写。IQA28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-91376-0.htmlSpringBoot多租户三种架构实现方案详解

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 聊聊主流消息队列的认证和鉴权!

下一篇: 京东二面:为什么Netty要创造FastThreadLocal?

标签:
  • 热门焦点
  • iPhone卖不动了!苹果股价创年内最大日跌幅:市值一夜蒸发万亿元

    iPhone卖不动了!苹果股价创年内最大日跌幅:市值一夜蒸发万亿元

    8月5日消息,今天凌晨美股三大指数高开低走集体收跌,道指跌0.41%;纳指跌0.36%;标普500指数跌0.52%。热门科技股也都变化极大,其中苹果报181.99美元,跌4.8%,创
  • 印度登月最关键一步!月船三号今晚进入环月轨道

    印度登月最关键一步!月船三号今晚进入环月轨道

    8月5日消息,据印度官方消息,月船三号将于北京时间今晚21时30分左右开始近月制动进入环月轨道。这是该探测器能够成功的最关键步骤之一,如果成功将开始围
  • Flowable工作流引擎的科普与实践

    Flowable工作流引擎的科普与实践

    一.引言当我们在日常工作和业务中需要进行各种审批流程时,可能会面临一系列技术和业务上的挑战。手动处理这些审批流程可能会导致开发成本的增加以及业务复杂度的上升。在这
  • 让我们一起聊聊文件的操作

    让我们一起聊聊文件的操作

    文件【1】文件是什么?文件是保存数据的地方,是数据源的一种,比如大家经常使用的word文档、txt文件、excel文件、jpg文件...都是文件。文件最主要的作用就是保存数据,它既可以保
  • Temu起诉SHEIN,跨境电商战事升级

    Temu起诉SHEIN,跨境电商战事升级

    来源 | 伯虎财经(bohuFN)作者 | 陈平安日前据外媒报道,拼多多旗下跨境电商平台Temu正对竞争对手SHEIN提起新诉讼,诉状称Shein&ldquo;利用市场支配力量强迫服装厂商与之签订独家
  • 拼多多APP上线本地生活入口,群雄逐鹿万亿市场

    拼多多APP上线本地生活入口,群雄逐鹿万亿市场

    Tech星球(微信ID:tech618)文 | 陈桥辉 Tech星球独家获悉,拼多多在其APP内上线了&ldquo;本地生活&rdquo;入口,位置较深,位于首页的&ldquo;充值中心&rdquo;内,目前主要售卖美食相关的
  • 阿里大调整

    阿里大调整

    来源:产品刘有媒体报道称,近期淘宝天猫集团启动了近年来最大的人力制度改革,涉及员工绩效、层级体系等多个核心事项,目前已形成一个初步的&ldquo;征求意见版&rdquo;:1、取消P序列
  • 三星折叠屏手机去年销售近1000万台 今年目标定为1500万

    三星折叠屏手机去年销售近1000万台 今年目标定为1500万

    7月29日消息,三星率先发力可折叠手机市场,在全球市场已经取得了非常亮眼的成绩,接下来会进一步巩固和扩大这一优势。三星在推出Galaxy Z Flip5和Galax
  • 质感不错!OPPO K11渲染图曝光:旗舰IMX890传感器首次下放

    质感不错!OPPO K11渲染图曝光:旗舰IMX890传感器首次下放

    一直以来,OPPO K系列机型都保持着较为均衡的产品体验,历来都是2K价位的明星机型,去年推出的OPPO K10和OPPO K10 Pro两款机型凭借各自的出色配置,堪称有
Top