基于MybatisPlus插件TenantLineInnerInterceptor实现多租户功能

实现多租户功能可以使用MybatisPlus插件TenantLineInnerInterceptor,该插件内部通过拦截SQL语句,并在SQL语句中添加租户ID的条件,从而实现多租户数据隔离。

实现步骤

1. 添加MybatisPlus依赖

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>最新版本</version>
</dependency>

2. 创建租户实体类

创建一个租户实体类,包含租户ID和租户名称等属性。例如:

@Data
public class Tenant {
    private Long id;
    private String name;
}

3. 配置多租户拦截器

MybatisPlusConfig类中配置多租户拦截器TenantLineInnerInterceptor

@Configuration
public class MybatisPlusConfig {

    @Autowired
    private DataSource dataSource;

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new TenantLineHandler() {
            @Override
            public Expression getTenantId() {
                // 从当前线程中获取租户ID,用于添加到SQL语句中
                Long tenantId = TenantContext.getTenantId();
                if (tenantId != null) {
                    return new LongValue(tenantId);
                } else {
                    throw new RuntimeException("获取租户ID失败");
                }
            }

            @Override
            public String getTenantIdColumn() {
                // 指定对应数据库表中存储租户ID的字段名
                return "tenant_id";
            }

            @Override
            public boolean ignoreTable(String tableName) {
                // 忽略的表名,如系统公共表,不需要加租户ID条件
                return tableName.equalsIgnoreCase("sys_config");
            }
        }));
        return interceptor;
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        factory.setPlugins(mybatisPlusInterceptor());
        return factory.getObject();
    }
}

在上面的代码中,我们使用TenantLineInnerInterceptor作为多租户拦截器,并创建一个TenantLineHandler实现类,并注入TenantLineInnerInterceptor中。

TenantLineHandler实现类中,我们需要实现3个方法:

  • getTenantId()方法:从当前线程中获取租户ID,用于添加到SQL语句中。
  • getTenantIdColumn()方法:指定对应数据库表中存储租户ID的字段名。
  • ignoreTable()方法:指定忽略的表名,不需要加租户ID条件。

4. 操作数据库

在具体操作数据库的地方,设置当前线程的租户ID。

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    @Override
    public void addUser(User user) {
        // 设置当前线程的租户ID
        TenantContext.setTenantId(user.getTenantId());

        userDao.insert(user);
    }

    @Override
    public void deleteUserById(Long userId) {
        // 设置当前线程的租户ID
        User user = userDao.selectById(userId);
        TenantContext.setTenantId(user.getTenantId());

        userDao.deleteById(userId);
    }

}

在上面的代码中,我们使用TenantContext类来设置当前线程的租户ID,该类通过ThreadLocal来实现。

示例说明

示例1

在实际使用中,我们可以将多租户拦截器和DataSource配置文件分离,单独在application.yml中进行配置。

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/test?serverTimezone=GMT%2B8
    username: root
    password: 123456

mybatis-plus:
  mapper-locations: classpath:/mapper/**/*.xml
  type-aliases-package: com.example.demo.entity
  global-config:
    db-config:
      id-type: auto
    banner: false
  configuration:
    map-underscore-to-camel-case: true
  interceptor:
    - com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor
  tenant-line:
    tenant-id-column: tenant_id
    ignore-tables: sys_config

在上面的配置中,我们使用interceptortenant-line来配置多租户拦截器,并指定租户ID字段名和忽略的表名。

示例2

在使用多租户拦截器时,由于需要从当前线程中获取租户ID,因此需要先在UserServiceImpl类中设置当前线程的租户ID。例如:

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    @Override
    public void addUser(User user) {
        TenantContext.setTenantId(user.getTenantId());

        userDao.insert(user);
    }

    @Override
    public void deleteUserById(Long userId) {
        User user = userDao.selectById(userId);
        TenantContext.setTenantId(user.getTenantId());

        userDao.deleteById(userId);
    }

}

在这种情况下,如果其他线程并发访问时可能导致租户ID被覆盖,从而出现数据错误。因此,我们可以使用AOP技术,在调用业务方法前动态设置租户ID。例如:

@Aspect
@Component
public class TenantAspect {

    @Before("execution(* com.example.demo.service.*.*(..)) && args(param,..)")
    public void before(JoinPoint joinPoint, Object param) {
        if (param instanceof TenantSupport) {
            Long tenantId = ((TenantSupport) param).getTenantId();
            TenantContext.setTenantId(tenantId);
        } else {
            throw new RuntimeException("实现接口TenantSupport才能使用多租户功能");
        }
    }

}

在上面的代码中,我们定义了一个AOP切面,在调用业务方法前动态解析TenantSupport接口中的租户ID,并设置到当前线程中。

使用该方式时,需要让需要实现多租户的实体类实现TenantSupport接口,例如:

@Data
public class User implements TenantSupport {
    private Long id;
    private String username;
    private String password;
    private Long tenantId;
}

在上面的代码中,我们让User实体类实现了TenantSupport接口,并在其中添加了tenantId属性作为租户ID。在实际使用中,通过设置该属性的值来动态设置租户ID。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:基于MybatisPlus插件TenantLineInnerInterceptor实现多租户功能 - Python技术站

(0)
上一篇 2023年5月17日
下一篇 2023年5月17日

相关文章

  • 分布式场景下,如何对外提供易变的服务,打造可靠的注册中心?

    摘要:本文讲了关于服务发现的很多干货内容,核心内容为服务发现组件的选择、网关的介绍、 客户端侧如何发给已发现的服务。 本文分享自华为云社区《分布式场景下,如何对外提供易变的服务,打造可靠的注册中心?》,作者:breakDawn。 随着云原生的概念越来越火,服务的架构应该如何发展和演进,成为很多程序员关心的话题。大名鼎鼎的《深入理解java虚拟机》一书作者于2…

    云计算 2023年5月6日
    00
  • Python使用MapReduce编程模型统计销量

    Python使用MapReduce编程模型统计销量 什么是MapReduce编程模型? MapReduce编程模型是一种用于处理大型数据集的并行计算模型。它由 Google 公司提出并应用到了 Google 的分布式文件系统(GFS)上。 该模型将一个大的计算任务分成许多小的任务,然后对这些小的任务进行并行处理,最后将每个小任务的结果合并起来,得到最终结果。…

    云计算 2023年5月18日
    00
  • 基于python实现地址和经纬度转换

    基于Python实现地址和经纬度转换 在Python应用程序中,有时需要将地址转换为经纬度,或将经纬度转换为地址。本文将提供一个完整的攻略,包括如何使用Python实现地址和经纬度转换。以下是详细步骤: 步骤1:安装必要的库 在使用Python实现地址和经纬度转换之前,我们需要安装必要的库。以下是一个示例说明,演示如何安装必要的库: pip install …

    云计算 2023年5月16日
    00
  • 云计算不可及?私有云对IT架构三大影响

    私有云,是指企业自己使用的云,它所有的服务不是供别人使用,而是供自己内部人员或分支机构使用。私有云的部署比较适合于有众多分支机构的大型企业或政府部门。相对于公有云,私有云部署在企业自身内部,因此其数据安全性、系统可用性都可由自己控制。但其缺点是投资较大,尤其是一次性的建设投资较大。   就云计算目前的大趋势来说,公有云的发展速度明显没有私有云快,私有云是大企…

    云计算 2023年4月11日
    00
  • 云计算运维学习—vim的简单使用

    vim的使用其实是学习Linux系统最基础的部分,这次主要是和大家分享一下vim使用中一些小技巧,便于快速操作。tips:CentOS7系统中默认是没有vim这个编辑器的,它自带的是vi编辑器,所以需要安装一下vim的安装包。使用vim的理由就是vim在vi面前是个爸爸。vim的简单使用vim的三种模式:01.命令模式02.插入模式(编辑模式)03.底行模式…

    云计算 2023年4月13日
    00
  • 七牛云储存创始人分享七牛的创立故事与对Go语言的应用

    七牛云储存创始人分享七牛的创立故事与对Go语言的应用 七牛云储存是一家提供云存储、CDN加速、数据处理等服务的公司,其创始人许道军曾分享了七牛的创立故事以及对Go语言的应用。下面是一份关于七牛云储存创始人分享的完整攻略,包括背景介绍、创立故事、对Go语言的应用、示例说明等。 1. 背景介绍 七牛云储存是一家提供云存储、CDN加速、数据处理等服务的公司,其创始…

    云计算 2023年5月16日
    00
  • Python脚本实现虾米网签到功能

    Python脚本实现虾米网签到功能 简介 虾米网是一款流行的音乐网站,用户可以在虾米网上听音乐、发现音乐、交流音乐。虾米网每日有签到功能,用户可以通过签到获取积分,积分可以用于兑换虾米网的一些礼品。 本文主要介绍使用Python脚本实现虾米网签到功能的方法,以及如何在脚本中模拟用户登录,实现自动签到。 实现步骤 1. 获取登录页面的cookie和code 在…

    云计算 2023年5月18日
    00
  • ajax跨域请求js拒绝访问的解决方法

    下面是关于“ajax跨域请求js拒绝访问的解决方法”的完整攻略,包含两个示例说明。 简介 在Web开发中,经常需要使用Ajax进行跨域请求。但是,由于浏览器的同源策略,可能会出现JavaScript拒绝访问的问题。本文将详细讲解如何解决Ajax跨域请求JavaScript拒绝访问的问题。 步骤 以下是解决Ajax跨域请求JavaScript拒绝访问的步骤: …

    云计算 2023年5月16日
    00
合作推广
合作推广
分享本页
返回顶部