一、介紹
MybaitsPlus多租戶處理器是一個對于多租戶問題的解決方案,主要的方案就是使用jSqlParser對sql進行決議,然后拼接租戶id來實作多個租戶之間的隔離,并且在洗掉、添加、修改和查詢等操作時都會拼接租戶ID
如:
SELECT * FROM info
處理后:
SELECT * FROM info WHERE tenant_id = 'tenant_id'
二、使用
以下復制的官方的demo,官方demo地址:https://gitee.com/baomidou/mybatis-plus-samples/tree/master/mybatis-plus-sample-tenant
package com.baomidou.mybatisplus.samples.tenant.config;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
/**
* @author miemie
* @since 2018-08-10
*/
@Configuration
@MapperScan("com.baomidou.mybatisplus.samples.tenant.mapper")
public class MybatisPlusConfig {
/**
* 新多租戶插件配置,一緩和二緩遵循mybatis的規則,需要設定 MybatisConfiguration#useDeprecatedExecutor = false 避免快取萬一出現問題
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new TenantLineHandler() {
@Override
public Expression getTenantId() {
return new LongValue(1);
}
// 這是 default 方法,默認回傳 false 表示所有表都需要拼多租戶條件
@Override
public boolean ignoreTable(String tableName) {
return !"user".equalsIgnoreCase(tableName);
}
}));
// 如果用了分頁插件注意先 add TenantLineInnerInterceptor 再 add PaginationInnerInterceptor
// 用了分頁插件必須設定 MybatisConfiguration#useDeprecatedExecutor = false
// interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
@Bean
public ConfigurationCustomizer configurationCustomizer() {
return configuration -> configuration.setUseDeprecatedExecutor(false);
}
}
是不是小伙伴們感覺僅僅是關鍵的一個組態檔就可以搞定了,用多租戶處理器之后就再也不用自己手動進行租戶ID的拼接了,那接下來跟大家說一下避坑的地方,
三、避坑
1、語法
在介紹中跟各位小伙伴們說了mybatis-plus使用的是jsqlparser來實作的,mybatis-plus使用jsqlparser來對語法進行決議并且使用jsqlparser來進行拼接租戶id的,
然而jsqlparser是對于sql的規范來進行決議的,如果出現一些特別的語法,
如示例:
SELECT CAST('1' as SIGNED)
經常用mysql的小伙伴們應該很熟悉這是一個字串轉換成數字的,而這種的jsqlparser就會報sql語法決議的一些錯誤,所以希望大家使用別的方法來替代如:
SELECT CONVERT('1', SIGNED)
2、表名問題
在使用多租戶處理器的時候往往很多表是不需要進行租戶id判斷的,這里作者的處理方式是將不需要租戶id判斷的表放到組態檔中,并且使用以下進行判斷,
@Value("${system.tenant.not-tenant-tables:null}")
private TreeSet<String> notTenantIdTable;
@Override
public boolean doTableFilter(String tableName) {
return notTenantIdTable.contains(tableName.toLowerCase());
}
這里看上去沒啥問題,但是需要注意表名的大小寫,以及``這種轉義符號
3、insert sql問題
作者在使用多租戶處理器的時候是在專案后期階段,這時候大部分業務代碼已經寫完了,插入sql都是自己手動獲取并且插入的,但是mybatis-plus的多租戶處理器已經想到這個問題了,啟用多租戶處理器的時候就會自動插入租戶ID,你自己插入了租戶ID,多租戶處理器也給你插入了租戶ID就會出現以下sql:
INSERT INTO info(id, tenant_id, tenant_id) VALUES(1, 'tenant_id', 'tenant_id')
這時候mysql就會毫不留情的報錯,解決這個的辦法其實也很簡單,不插入租戶ID了唄,當然也可以用以下辦法解決
1、繼承TenantSqlParser
/**
* 多租戶sql決議器擴展
* @author weicong
* @version 1.0 createTime 2021-2-22 20:05:58
*/
public class TenantSqlParserExt extends TenantSqlParser {
/**
* 是否處理插入的sql
*/
private boolean isHandlerInsert = true;
/**
* 是否處理查詢的sql
*/
private boolean isHandlerSelect = true;
@Override
public void processInsert(Insert insert) {
if(isHandlerInsert){
int index = findTenantIdColumnIndex(insert.getColumns());
//若不存在租戶ID則進行添加租戶ID資訊
if(-1 == index){
super.processInsert(insert);
}
}
}
/**
* 獲取Column集合中租戶ID的位置,若沒有回傳-1
* @param columns
* @return
*/
public int findTenantIdColumnIndex(List<Column> columns){
Column column;
for(int i = 0; i < columns.size(); i++){
column = columns.get(i);
if(Global.TENANT_ID_COLUMN.equals(column.getColumnName())){
return i;
}
}
return -1;
}
@Override
public void processSelectBody(SelectBody selectBody) {
if(isHandlerSelect){
super.processSelectBody(selectBody);
}
}
public boolean isHandlerInsert() {
return isHandlerInsert;
}
public void setHandlerInsert(boolean handlerInsert) {
isHandlerInsert = handlerInsert;
}
public boolean isHandlerSelect() {
return isHandlerSelect;
}
public void setHandlerSelect(boolean handlerSelect) {
isHandlerSelect = handlerSelect;
}
}
2、配置TenantSqlParser
/**
* 初始化多租戶處理器
* @param paginationInterceptor
*/
public void initTenantHandler(PaginationInterceptor paginationInterceptor){
ArrayList<ISqlParser> sqlParsers = new ArrayList<>();
TenantSqlParser tenantSqlParser = new TenantSqlParserExt();
tenantSqlParser.setTenantHandler(new TenantHandler() {
@Override
public Expression getTenantId(boolean where) {
return new LongValue(LoginUserUtils.getTenantId());
}
@Override
public String getTenantIdColumn() {
return Global.TENANT_ID_COLUMN;
}
@Override
public boolean doTableFilter(String tableName) {
tableName = clearSymbol(tableName);
boolean is = tenantProperties.getNotTenantIdTable().contains(tableName.toLowerCase());
return is;
}
});
sqlParsers.add(tenantSqlParser);
paginationInterceptor.setSqlParserList(sqlParsers);
}
四、總結
本文已經介紹了介紹了mybaits-plus多租戶處理器的使用以及避坑指南,作者已經整理了完整demo來提供大家參考,如果有問題請大家評論或進入Q群415777345找作者,本文純手寫,
gitee:https://gitee.com/nightowl7/mybatis-plus-tenant-demo
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/263308.html
標籤:其他
