mybatis 多租户saas_springboot搭建SaaS多租户动态数据源

编程知识 更新时间:2023-05-02 22:22:06

一、SAAS是什么

SaaS是Software-as-a-service(软件即服务)它是一种通过Internet提供软件的模式,厂商将应用软件统一部署在自己的服务器上,客户可以根据自己实际需求,通过互联网向厂商定购所需的应用软件服务,按定购的服务多少和时间长短向厂商支付费用,并通过互联网获得厂商提供的服务。用户不用再购买软件,而改用向提供商租用基于Web的软件,来管理企业经营活动,且无需对软件进行维护,服务提供商会全权管理和维护软件。

二、SAAS模式有哪些角色

①服务商:服务商主要是管理租户信息,按照不同的平台需求可能还需要统合整个平台的数据,作为大数据的基础。服务商在SAAS模式中是提供服务的厂商。

②租户:租户就是购买/租用服务商提供服务的用户,租户购买服务后可以享受相应的产品服务。现在很多SAAS化的产品都会划分

系统版本,不同的版本开放不同的功能,还有基于功能收费之类的,不同的租户购买不同版本的系统后享受的服务也不一样。

三、SAAS模式有哪些特点

①独立性:每个租户的系统相互独立。

②平台性:所有租户归平台统一管理。

③隔离性:每个租户的数据相互隔离。

在以上三个特性里面,SAAS系统中最重要的一个标志就是数据隔离性,租户间的数据完全独立隔离。

四、数据隔离有哪些方案

①独立数据库

即一个租户一个数据库,这种方案的用户数据隔离级别最高,安全性最好,但成本较高。

优点:

为不同的租户提供独立的数据库,有助于简化数据模型的扩展设计,满足不同租户的独特需求,如果出现故障,恢复数据比较简单。

缺点:

增多了数据库的安装数量,随之带来维护成本和购置成本的增加。 如果定价较低,产品走低价路线,这种方案一般对运营商来说是无法承受的。

②共享数据库,隔离数据架构

即多个或所有租户共享数据库,但是每个租户一个Schema。

优点:

为安全性要求较高的租户提供了一定程度的逻辑数据隔离,并不是完全隔离,每个数据库可支持更多的租户数量。

缺点:

如果出现故障,数据恢复比较困难,因为恢复数据库将牵涉到其他租户的数据 如果需要跨租户统计数据,存在一定困难。

③共享数据库,共享数据架构

即租户共享同一个数据库、同一个Schema,但在表中增加TenantID多租户的数据字段。这是共享程度最高、隔离级别最低的模式。

优点:

三种方案比较,第三种方案的维护和购置成本最低,允许每个数据库支持的租户数量最多。

缺点:

隔离级别最低,安全性最低,需要在设计开发时加大对安全的开发量,数据备份和恢复最困难,需要逐表逐条备份和还原。

如果希望以最少的服务器为最多的租户提供服务,并且租户接受牺牲隔离级别换取降低成本,这种方案最适合。

五、基于springboot、mybatis-plus实现动态切换数据源

以下内容是基于上述方案的第一种方案实现的,每个租户都有自己独立的数据库,在一张数据源表中记录所有租户的数据库连接信息

1. 自定义动态数据源

要实现动态切换数据源,首先需要替换掉默认mybatis使用的数据源,我们自己定义一个数据源DynamicDataSource

springboot 提供了AbstractRoutingDataSource 根据用户定义的规则选择当前的数据源。

package com.example.tenant.config;

import com.alibaba.druid.pool.DruidDataSource;

import com.example.tenant.dto.TenantDatasourceDTO;

import lombok.extern.slf4j.Slf4j;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import javax.sql.DataSource;

import java.util.Map;

/**

* 自定义一个数据源

*/

@Slf4j

public class DynamicDataSource extends AbstractRoutingDataSource {

/**

* 用于保存租户key和数据源的映射关系,目标数据源map的拷贝

*/

public Map backupTargetDataSources;

/**

* 动态数据源构造器

* @param defaultDataSource 默认数据源

* @param targetDataSource 目标数据源映射

*/

public DynamicDataSource(DataSource defaultDataSource, Map targetDataSource){

backupTargetDataSources = targetDataSource;

super.setDefaultTargetDataSource(defaultDataSource);

// 存放数据源的map

super.setTargetDataSources(backupTargetDataSources);

// afterPropertiesSet 的作用很重要,它负责解析成可用的目标数据源

super.afterPropertiesSet();

}

/**

* 必须实现其方法

* 动态数据源类集成了Spring提供的AbstractRoutingDataSource类,AbstractRoutingDataSource

* 中获取数据源的方法就是 determineTargetDataSource,而此方法又通过 determineCurrentLookupKey 方法获取查询数据源的key

* 通过key在resolvedDataSources这个map中获取对应的数据源,resolvedDataSources的值是由afterPropertiesSet()这个方法从

* TargetDataSources获取的

*

* @return

*/

@Override

protected Object determineCurrentLookupKey() {

return DataSourceContextHolder.getDBType();

}

/**

* 添加数据源到目标数据源map中

* @param datasource

*/

public void addDataSource(TenantDatasourceDTO datasource) {

DruidDataSource druidDataSource = new DruidDataSource();

druidDataSource.setUrl(datasource.getUrl());

druidDataSource.setUsername(datasource.getUsername());

druidDataSource.setPassword(datasource.getPassword());

// 将传入的数据源对象放入动态数据源类的静态map中,然后再讲静态map重新保存进动态数据源中

backupTargetDataSources.put(datasource.getTenantKey(), druidDataSource);

super.setTargetDataSources(backupTargetDataSources);

super.afterPropertiesSet();

}

}

2. mybatis数据源配置

配置mybatis数据源使用自定义的动态数据源

@Configuration

@MapperScan({"com.example.tenant.mapper"})

public class MybatisConfigurer {

/**

* 配置文件yml中的默认数据源

* @return

*/

@Bean(name = "defaultDataSource")

@ConfigurationProperties(prefix="spring.datasource")

public DataSource getDefaultDataSource() {

return DruidDataSourceBuilder.create().build();

}

/**

* 将动态数据源对象放入spring中管理

* @return

*/

@Bean

public DynamicDataSource dynamicDataSource() {

Map targetDataSources = new HashMap<>();

log.info("将druid数据源放入默认动态数据源对象中");

targetDataSources.put(GlobalConstant.TENANT_CONFIG_KEY, getDefaultDataSource());

return new DynamicDataSource(getDefaultDataSource(), targetDataSources);

}

/**

* 数据库连接会话工厂

* @param dynamicDataSource 自定义动态数据源

* @return

* @throws Exception

*/

@Bean

public SqlSessionFactory sqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dynamicDataSource) throws Exception {

MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();

bean.setDataSource(dynamicDataSource);

bean.setMapperLocations(new PathMatchingResourcePatternResolver()

.getResources("classpath*:mapper/**/*.xml"));

return bean.getObject();

}

@Bean

public SqlSessionTemplate sqlSessionTemplate(@Qualifier("sqlSessionFactory") SqlSessionFactory sqlSessionFactory){

return new SqlSessionTemplate(sqlSessionFactory);

}

}

3. 数据源上下文

创建数据源上下文用于统一每次请求的数据源,通过threadlocal确保在一个线程内使用同一个数据源

public class DataSourceContextHolder {

private static final ThreadLocal contextHolder = new InheritableThreadLocal();

/**

* 保存租户id

* @param dbType 租户id

*/

public static void setDBType(String dbType){

contextHolder.set(dbType);

}

public static String getDBType(){

return contextHolder.get();

}

public static void clearDBType(){

contextHolder.remove();

}

}

4. 初始化数据源

程序启动时从数据库中读取所有租户的数据库连接配置信息,初始化数据源放入动态数据源对象DynamicDataSource的TargetDataSources中

@Component

@Order(value = 1)

@Slf4j

public class SystemInitRunner implements ApplicationRunner {

@Resource

private DatasourceMapper tenantDatasourceMapper;

@Autowired

private DynamicDataSource dynamicDataSource;

@Override

public void run(ApplicationArguments args) {

//租户端不进行服务调用

log.info("==服务启动后,初始化数据源==");

//切换默认数据源 即tenant库的数据源,用于查询tenant表中的所有tenant数据库配置

DataSourceContextHolder.setDBType("default");

//设置所有数据源信息

log.info("获取当前数据源:" + DataSourceContextHolder.getDBType());

List tenantInfoList = tenantDatasourceMapper.selectList(null);

for (Datasource info : tenantInfoList) {

TenantDatasourceDTO tenantDatasourceDTO = new TenantDatasourceDTO();

BeanUtils.copyProperties(info, tenantDatasourceDTO);

dynamicDataSource.addDataSource(tenantDatasourceDTO);

}

log.info("动态数据源对象中的所有数据源, 已加载数据源个数: {}", dynamicDataSource.backupTargetDataSources.size());

log.info("初始化多租户数据库配置完成...");

}

}

数据库表结构

更多推荐

mybatis 多租户saas_springboot搭建SaaS多租户动态数据源

本文发布于:2023-04-29 01:52:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/a995deb5724cfc038fabb802d123de62.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:租户   数据源   动态   mybatis   SaaS

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!

  • 109862文章数
  • 27918阅读数
  • 0评论数