基于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日

相关文章

  • 接口数据安全保证的10种方式

    下面是关于“接口数据安全保证的10种方式”的完整攻略,包含两个示例说明。 简介 在Web应用程序中,接口数据安全是非常重要的。在本攻略中,我们将介绍10种保证接口数据安全的方式,并提供两个示例说明。 10种方式 以下是10种保证接口数据安全的方式: 使用HTTPS协议。 对接口进行身份验证。 对接口进行访问控制。 对接口进行数据加密。 对接口进行数据签名。 …

    云计算 2023年5月16日
    00
  • 什么是CRM?CRM的常见类型有哪些?

    什么是CRM? CRM是客户关系管理(Customer Relationship Management)的缩写,是一种通过技术手段来管理和优化企业与客户之间关系的方法。CRM系统可以帮助企业更好地了解客户需求,提高客户满意度,增加销售额和利润。 CRM的常见类型 1. 操作型CRM 操作型CRM是指通过技术手段来管理和优化企业与客户之间关系的方法。操作型CR…

    云计算 2023年5月16日
    00
  • 价值100亿美元!微软刚刚击败亚马逊,拿下美国国防部十年云计算基建订单

    大数据文摘授权编译自《纽约时报》编译:李雷、曹培信、刘俊寰 为期10年,价值100亿美元。 经过长达一年的竞标,微软接连击败了谷歌、IBM、Oracle和亚马逊,拿下了美国国防部云计算这宝贵的一单。 上周五,美国国防部发布了官方声明,价值100亿美元的大型云计算合同“联合企业国防基建”(Joint Enterprise Defense Infrastruct…

    云计算 2023年4月12日
    00
  • Angularjs之如何在跨域请求中传输Cookie的方法

    要在跨域请求中传输cookie,需要注意以下几点: 后端服务需要设置允许跨域请求,并设置Access-Control-Allow-Credentials为true。例如,node.js中的跨域设置代码如下: app.all(‘*’, function(req, res, next) { res.header("Access-Control-Allo…

    云计算 2023年5月17日
    00
  • ASP.net WebAPI 上传图片实例

    下面我详细讲解一下“ASP.net WebAPI 上传图片实例”的完整攻略。 一、准备工作 在进行图片上传之前,需要先在项目中添加相应的 NuGet 包,具体步骤如下: 打开 Visual Studio,打开项目,右键点击项目名称,选择“Manage NuGet Packages…”。 在“NuGet 包管理器”中搜索“Microsoft.AspNet.…

    云计算 2023年5月17日
    00
  • 10家大厂面试真题(虐到哭)

    10家大厂面试真题(虐到哭)攻略 1. 背景介绍 在求职过程中,面试是一个非常重要的环节。为了更好地应对面试,我们需要提前了解一些面试题目和面试技巧。本文将介绍10家大厂面试真题,并提供相应的攻略和示例说明,帮助读者更好地应对面试。 2. 面试真题 以下是10家大厂面试真题: 请实现一个函数,将一个字符串中的空格替换成“%20”。 请实现一个函数,判断一个字…

    云计算 2023年5月16日
    00
  • Android SQLite数据库中的表详解

    Android SQLite数据库中的表详解 什么是SQLite数据库 SQLite是一种轻量级的关系型数据库管理系统,它被广泛用于应用程序中,适用于存储和管理较小的、离线的数据。在Android中,SQLite是官方推荐使用的本地数据存储方式之一,适用于各种类型的数据存储需求。 什么是SQLite表 在SQLite数据库中,表是存储数据的主要对象。表可以看…

    云计算 2023年5月18日
    00
  • 大数据、云计算…34亿的新基建,怎么才能薅到这波“数字红利”

    十年前,我们错过了传统基建这一风口上的红利,十年后,新基建带着新的风口向我们招手,没薅到传统基建的羊毛,这次就一定要薅到新基建的羊毛,但是我们应该怎么才能薅到这波“数字红利”?      什么是新基建 4月20日,国家发改委召开新闻发布会,首次明确了新基建的范围,更是将5G、物联网、人工智能、云计算、区块链、大数据等词再一次带上热搜。在说新基建之前,我们要先…

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