Mybatis plus多租户方案的实战踩坑记录
什么是多租户
多租户,即多租户架构,是一种软件架构模式,指的是多个客户(租户)共用相同的软件应用系统、数据库和服务器等资源,并且每个租户数据是彼此独立,系统中一个租户的数据不能被其他租户访问。
Mybatis plus多租户
Mybatis plus是Mybatis的增强版,提供了多租户的支持,可以通过配置自动根据租户ID进行数据的隔离,避免了在代码层面对租户进行手动过滤,提高了开发效率和代码可维护性。
实现步骤
- 引入依赖
在pom.xml中引入Mybatis plus的依赖:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
- 配置多租户插件
在配置文件中加入以下配置:
mybatis-plus:
configuration:
#开启多租户支持
map-underscore-to-camel-case: true
mapper-locations: classpath:mapper/**/*.xml
configuration:
# SQL执行时多租户条件的拼接器
multi-tenant-handler: com.example.demo.config.MybatisMultiTenantHandler
# 多租户类型,目前支持SCHEMA、TABLE
multi-tenant-type: SCHEMA
# 多租户标识一般为租户ID字段名
tenant-column: tenant_id
配置中multi-tenant-handler
属性用于指定多租户的处理器类,multi-tenant-type
属性用于指定多租户的类型(SCHEMA或者TABLE),tenant-column
属性用于指定租户ID的字段名。
- 实现多租户处理器
在MybatisMultiTenantHandler类中,我们需要实现一个TenantHandler接口,这个接口需要实现3个方法:
@Component
public class MybatisMultiTenantHandler implements TenantHandler {
//返回租户Id的值,可以通过此方法获取到当前请求所属的租户Id
@Override
public Expression getTenantId(boolean select) {
return new LongValue(getCurrentTenantId());
}
//指定哪些表需要多租户的支持
@Override
public String getTenantIdColumn() {
return "tenant_id";
}
//租户字段类型
@Override
public TenantColumnType getTenantColumnType() {
return TenantColumnType.LONG;
}
private Long getCurrentTenantId(){
//根据请求所属的租户可以获取到当前租户的ID
return TenantContext.getCurrentTenantId();
}
}
在实现中,可以通过TenantContext.getCurrentTenantId()
方法获取到当前请求所属的租户ID,并通过getTenantColumnType()
方法指定租户字段的类型。
- 实现多租户上下文
在全局上下文中保存当前请求租户的ID,这个可以通过实现一个过滤器或拦截器来完成。
public class TenantContext {
private static ThreadLocal<Long> currentTenant = new ThreadLocal<>();
public static Long getCurrentTenantId(){
return currentTenant.get();
}
public static void setCurrentTenantId(Long tenantId){
currentTenant.set(tenantId);
}
public static void clear(){
currentTenant.remove();
}
}
然后编写过滤器或拦截器,在请求进入Controller之前,从请求头或者参数中获取到当前请求所属的租户ID,并保存到全局上下文中。
@Component
public class TenantInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String tenantIdStr = request.getHeader("tenantId");
if(StringUtils.isEmpty(tenantIdStr)){
tenantIdStr = request.getParameter("tenantId");
}
if(StringUtils.isEmpty(tenantIdStr)){
throw new RuntimeException("tenantId not found");
}
Long tenantId = Long.parseLong(tenantIdStr);
TenantContext.setCurrentTenantId(tenantId);
return true;
}
}
- 测试
在需要进行多租户隔离的Mapper中,添加租户ID的字段,并在查询和插入时使用多租户的支持即可。
public interface UserMapper extends BaseMapper<User> {
}
然后进行测试,可以通过修改请求头或请求参数中的租户ID,来切换不同的租户。
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTests {
@Autowired
private UserMapper userMapper;
@Test
public void testInsert() {
User user = new User();
user.setName("张三");
user.setAge(20);
userMapper.insert(user);
}
@Test
public void testSelectList(){
List<User> userList = userMapper.selectList(null);
System.out.println(userList);
}
}
示例说明
示例1
假设有一个线上电商平台,需要对每个商家进行数据隔离,实现租户的隔离。我们可以采用Mybatis plus的多租户方案来实现。
在商家表的数据中添加租户ID字段,然后在操作数据库时,使用多租户方案进行数据隔离。
示例2
假设有一个医院管理系统,需要对每个医院进行数据隔离,实现租户的隔离。我们可以采用Mybatis plus的多租户方案来实现。
在医院表的数据中添加租户ID字段,然后在操作数据库时,使用多租户方案进行数据隔离。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Mybatis plus多租户方案的实战踩坑记录 - Python技术站