广告
返回顶部
首页 > 资讯 > 精选 >如何使用Mybatis-plus实现多租户架构
  • 609
分享到

如何使用Mybatis-plus实现多租户架构

2023-06-29 03:06:32 609人浏览 八月长安
摘要

这篇文章给大家分享的是有关如何使用mybatis-plus实现多租户架构的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。多租户(Multi-Tenant)是SaaS中的一个重要概念,它是一种软件架构技术,在多个租户

这篇文章给大家分享的是有关如何使用mybatis-plus实现多租户架构的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。

多租户(Multi-Tenant)是SaaS中的一个重要概念,它是一种软件架构技术,在多个租户的环境下,共享同一套系统实例,并且租户之间的数据具有隔离性,也就是说一个租户不能去访问其他租户的数据。基于不同的隔离级别,通常具有下面三种实现方案:

每个租户使用独立DataBase,隔离级别高,性能好,但成本大

租户之间共享DataBase,使用独立的Schema

租户之间共享Schema,在表上添加租户字段,共享数据程度最高,隔离级别最低。

Mybatis-plus在第3层隔离级别上,提供了基于分页插件的多租户的解决方案,我们对此来进行介绍。在正式开始前,首先做好准备工作创建两张表,在基础字段后都添加租户字段tenant_id:

CREATE TABLE `user` (  `id` bigint(20) NOT NULL,  `name` varchar(20) DEFAULT NULL,  `phone` varchar(11) DEFAULT NULL,  `address` varchar(64) DEFAULT NULL,  `tenant_id` bigint(20) DEFAULT NULL,  PRIMARY KEY (`id`))CREATE TABLE `dept` (  `id` bigint(20) NOT NULL,  `dept_name` varchar(64) DEFAULT NULL,  `comment` varchar(128) DEFAULT NULL,  `tenant_id` bigint(20) DEFAULT NULL,  PRIMARY KEY (`id`))

项目中导入需要的依赖:

<dependency>    <groupId>com.baomidou</groupId>    <artifactId>mybatis-plus-boot-starter</artifactId>    <version>3.3.2</version></dependency><dependency>    <groupId>com.GitHub.jsqlparser</groupId>    <artifactId>jsqlparser</artifactId>    <version>3.1</version></dependency>

Mybatis-plus 配置类:

@EnableTransactionManagement(proxyTargetClass = true)@Configurationpublic class MybatisPlusConfig {    @Bean    public PaginationInterceptor paginationInterceptor() {        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();        List<ISqlParser> sqlParserList=new ArrayList<>();        TenantSqlParser tenantSqlParser=new TenantSqlParser();        tenantSqlParser.setTenantHandler(new TenantHandler() {            @Override            public Expression getTenantId(boolean select) {                               String tenantId = "3";                return new StringValue(tenantId);            }            @Override            public String getTenantIdColumn() {                return "tenant_id";            }            @Override            public boolean doTableFilter(String tableName) {                return false;            }        });        sqlParserList.add(tenantSqlParser);        paginationInterceptor.setSqlParserList(sqlParserList);        return paginationInterceptor;    }}

这里主要实现的功能:

  • 创建SQL解析器集合

  • 创建租户SQL解析器

  • 设置租户处理器,具体处理租户逻辑

这里暂时把租户的id固定写成3,来进行测试。测试执行全表语句:

public List<User> getUserList() {    return userMapper.selectList(new LambdaQueryWrapper<User>().isNotNull(User::getId));}

使用插件解析执行的SQL语句,可以看到自动在查询条件后加上了租户过滤条件:

如何使用Mybatis-plus实现多租户架构

那么在实际的项目中,怎么将租户信息传给租户处理器呢,根据情况我们可以从缓存或者请求头中获取,以从Request请求头获取为例:

@Overridepublic Expression getTenantId(boolean select) {    ServletRequestAttributes attributes=(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();    httpservletRequest request = attributes.getRequest();    String tenantId = request.getHeader("tenantId");    return new StringValue(tenantId);}

前端在发起Http请求时,在Header中加入tenantId字段,后端在处理器中获取后,设置为当前这次请求的租户过滤条件。

如果是基于请求头携带租户信息的情况,那么在使用中可能会遇到一个坑,如果当使用多线程的时候,新开启的异步线程并不会自动携带当前线程的Request请求。

@Overridepublic List<User> getUserListByFuture() {    Callable getUser=()-> userMapper.selectList(new LambdaQueryWrapper<User>().isNotNull(User::getId));    FutureTask<List<User>> future=new FutureTask<>(getUser);    new Thread(future).start();    try {        return future.get();    } catch (Exception e) {        e.printStackTrace();    }    return null;}

执行上面的方法,可以看出是获取不到当前的Request请求的,因此无法获得租户id,会导致后续报错空指针异常:

如何使用Mybatis-plus实现多租户架构

修改的话也非常简单,开启RequestAttributes的子线程共享,修改上面的代码:

@Overridepublic List<User> getUserListByFuture() {    ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();    Callable getUser=()-> {        RequestContextHolder.setRequestAttributes(sra, true);        return userMapper.selectList(new LambdaQueryWrapper<User>().isNotNull(User::getId));    };    FutureTask<List<User>> future=new FutureTask<>(getUser);    new Thread(future).start();    try {        return future.get();    } catch (Exception e) {        e.printStackTrace();    }    return null;}

这样修改后,在异步线程中也能正常的获取租户信息了。

那么,有的小伙伴可能要问了,在业务中并不是所有的查询都需要过滤租户条件啊,针对这种情况,有两种方式来进行处理。

如果整张表的所有SQL操作都不需要针对租户进行操作,那么就对表进行过滤,修改doTableFilter方法,添加表的名称:

@Overridepublic boolean doTableFilter(String tableName) {    List<String> IGNORE_TENANT_TABLES= Arrays.asList("dept");    return IGNORE_TENANT_TABLES.stream().anyMatch(e->e.equalsIgnoreCase(tableName));}

这样,在dept表的所有查询都不进行过滤:

如何使用Mybatis-plus实现多租户架构

如果有一些特定的SQL语句不想被执行租户过滤,可以通过@SqlParser注解的形式开启,注意注解只能加在Mapper接口的方法上:

@SqlParser(filter = true)@Select("select * from user where name =#{name}")User selectUserByName(@Param(value="name") String name);

或在分页拦截器中指定需要过滤的方法:

@Beanpublic PaginationInterceptor paginationInterceptor() {    PaginationInterceptor paginationInterceptor = new PaginationInterceptor();    paginationInterceptor.setSqlParserFilter(metaObject->{        MappedStatement ms = SqlParserHelper.getMappedStatement(metaObject);        // 对应Mapper、dao中的方法        if("com.cn.tenant.dao.UserMapper.selectUserByPhone".equals(ms.getId())){            return true;        }        return false;    });    ...}

上面这两种方式实现的功能相同,但是如果需要过滤的SQL语句很多,那么第二种方式配置起来会比较麻烦,因此建议通过注解的方式进行过滤。

除此之外,还有一个比较容易踩的坑就是在复制Bean时,不要复制租户id字段,否则会导致SQL语句报错:

public void createSnapshot(Long userId){    User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getId, userId));    UserSnapshot userSnapshot=new UserSnapshot();    BeanUtil.copyProperties(user,userSnapshot);    userSnapshotMapper.insert(userSnapshot);}

查看报错可以看出,本身Bean的租户字段不为空的情况下,SQL又自动添加一次租户查询条件,因此导致了报错:

如何使用Mybatis-plus实现多租户架构

我们可以修改复制Bean语句,手动忽略租户id字段,这里使用的是hutool的BeanUtil工具类,可以添加忽略字段。

BeanUtil.copyProperties(user,userSnapshot,"tenantId");

在忽略了租户id的拷贝后,查询可以正常执行。

最后,再来看一下对联表查询的支持,首先看一下包含子查询的SQL:

@Select("select * from user where id in (select id from user_snapshot)")List<User> selectSnapshot();

查看执行结果,可以看见,在子查询的内部也自动添加的租户查询条件:

如何使用Mybatis-plus实现多租户架构

再来看一下使用Join进行联表查询:

@Select("select u.* from user u left join user_snapshot us on u.id=us.id")List<User> selectSnapshot();

同样,会在左右两张表上都添加租户的过滤条件:

如何使用Mybatis-plus实现多租户架构

再看一下不使用Join的普通联表查询:

@Select("select u.* from user u ,user_snapshot us,dept d where u.id=us.id and d.id is not null")List<User> selectSnapshot();

如何使用Mybatis-plus实现多租户架构

查看执行结果,可以看见在这种情况下,只在FROM关键字后面的第一张表上添加了租户的过滤条件,因此如果使用这种查询方式,需要额外注意,用户需要手动在SQL语句中添加租户过滤。

感谢各位的阅读!关于“如何使用Mybatis-plus实现多租户架构”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

--结束END--

本文标题: 如何使用Mybatis-plus实现多租户架构

本文链接: https://www.lsjlt.com/news/322173.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 如何使用Mybatis-plus实现多租户架构
    这篇文章给大家分享的是有关如何使用Mybatis-plus实现多租户架构的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。多租户(Multi-Tenant)是SaaS中的一个重要概念,它是一种软件架构技术,在多个租户...
    99+
    2023-06-29
  • SpringBoot集成Mybatis-Plus多租户架构实现
    目录一. 什么是多租户二. 多租户架构以及数据隔离方案1. 独立数据库2. 共享数据库,独立 Schema3. 共享数据库,共享 Schema,共享数据表三.多租户架构适用场景?四....
    99+
    2022-11-12
  • 基于Mybatis-plus实现多租户架构的全过程
    多租户(Multi-Tenant)是SaaS中的一个重要概念,它是一种软件架构技术,在多个租户的环境下,共享同一套系统实例,并且租户之间的数据具有隔离性,也就是说一个租户不能去访问其...
    99+
    2022-11-13
  • 如何MyBatis在使用MyCat实现多租户功能
    本篇文章给大家分享的是有关如何MyBatis在使用MyCat实现多租户功能,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。MyCat 基本配置首先针对多租户配置了多个数据库,在 ...
    99+
    2023-05-31
    mybatis mycat
  • mybatis plus如何实现在Spring boot上使用
    mybatis plus如何实现在Spring boot上使用?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。maven依赖 <dependency> ...
    99+
    2023-05-31
    springboot mybatis
  • HBase如何实现多租户
    这篇文章主要介绍了HBase如何实现多租户,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。多租户(multi-tenancy technology),参考维基百科定义,它是在探...
    99+
    2023-06-02
  • 如何使用MyBatis Plus实现数据库curd操作
    目录1.mp是什么2、mp入门2.1、curd2.2、自动填充3、乐观锁3.1、场景4、MP查询4.1、多个ID批量查询4.2、简单条件查询(Map)4.3、分页查询5、MP删除5....
    99+
    2022-11-12
  • 如何使用mybatis-plus实现分页查询功能
    今天就跟大家聊聊有关使用mybatis-plus如何实现分页查询功能,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。 引入依赖...
    99+
    2022-11-13
  • Mybatis-Plus如何使用分页实例详解
    目录1.写个Mybatis-plus配置类:2.写接口测试3.注意4.如果你还有查询条件1.Lambda表达式2.普通查询总结 Mybatis-Plus(简称MP)是一个&...
    99+
    2022-11-13
  • 如何在springboot中使用mybatis-plus实现一个多表分页查询功能
    这篇文章将为大家详细讲解有关如何在springboot中使用mybatis-plus实现一个多表分页查询功能,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。新建一个springboot工程需要...
    99+
    2023-06-07
  • Mybatis Plus使用条件构造器增删改查功能的实现方法
    java后端层级结构 Controller 接口层 接口层比较好理解,它是面向web网络的接口,使用http格式去调用 @RestController @RequestMap...
    99+
    2022-11-12
  • 微服务架构如何处理多租户应用场景下的服务分离?
    随着互联网的发展,越来越多的企业开始构建多租户应用,以满足不同用户的需求。在这种场景下,微服务架构成为了一种常见的技术选择。然而,如何在微服务架构中处理多租户应用场景下的服务分离问题,仍然是一个值得探讨的话题。多租户应用场景下的服务架构在多...
    99+
    2023-05-17
    微服务架构 多租户应用场景 服务分离
  • 使用Linux 怎么实现文档多租户管理
    使用Linux 怎么实现文档多租户管理?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。创建账户相关信息groupadd microsoft ; 新增群组useradd -G ...
    99+
    2023-06-10
  • 在SpringBoot 中使用Mybatis Plus如何实现一个自动填充功能
    本篇文章为大家展示了在SpringBoot 中使用Mybatis Plus如何实现一个自动填充功能,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。一.应用场景平时在建对象表的时候都会有最后修改时间,最...
    99+
    2023-05-31
    springboot mybatis plus 自动填充
  • 使用Mybatis如何实现删除多个数据
    目录Mybatis删除多个数据删除数据库中sid=1和sid=2的数据操作步骤如下Mybatis批量删除多表数据业务需求查询以obj_前缀开头的表的截断语句Mybatis删除多个数据...
    99+
    2022-11-13
  • 如何使用Mybatis如何实现删除多个数据
    这篇文章将为大家详细讲解有关如何使用Mybatis如何实现删除多个数据,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。Mybatis删除多个数据例如:删除数据库中sid=1和sid=2的数据操作步骤如下1....
    99+
    2023-06-29
  • MyBatis-Plus使用条件构造器实现不同条件的查询,更新删除操作
    Wrapper 是所有条件构造器的父类,作用是生成条件语句,即where后面的sql子句 在调用查询,更新,删除操作时,需要根据条件进行判断,可以使用条件构造器进行组合条件,生成where后面条件子句 QueryWrap...
    99+
    2023-08-31
    sql mysql 数据库
  • 在springboot中使用mybatis如何实现多数据源
    这篇文章给大家介绍在springboot中使用mybatis如何实现多数据源,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。说起多数据源,一般都来解决那些问题呢,主从模式或者业务比较复杂需要连接不同的分库来支持业务。我们...
    99+
    2023-05-31
    springboot mybatis 多数据源
  • 如何基于LSM-tree架构实现一写多读
    一  前言 PolarDB是阿里巴巴自研的新一代云原生关系型数据库,在存储计算分离架构下,利用了软硬件结合的优势,为用户提供具备极致弹性、海量存储、高性能、低成本的数据库服务。X-Engine是阿里巴巴自研的新一代存储引擎,作为AliSQ...
    99+
    2016-12-28
    如何基于LSM-tree架构实现一写多读
  • 基于MybatisPlus插件TenantLineInnerInterceptor如何实现多租户功能
    这篇文章主要介绍基于MybatisPlus插件TenantLineInnerInterceptor如何实现多租户功能,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!多租户技术的基本概念:多租户技术(英语:multi-t...
    99+
    2023-06-21
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作