🐎 数据权限性能优化:对于无需数据权限控制的 sql 在解析一次后进行记录,后续不再进行解析处理
This commit is contained in:
@@ -3,9 +3,14 @@ package com.hccake.ballcat.common.datascope.handler;
|
||||
import com.hccake.ballcat.common.datascope.DataScope;
|
||||
import com.hccake.ballcat.common.datascope.annotation.DataPermission;
|
||||
import com.hccake.ballcat.common.datascope.holder.DataPermissionAnnotationHolder;
|
||||
import com.hccake.ballcat.common.datascope.holder.MappedStatementIdsWithoutDataScope;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -64,13 +69,17 @@ public class DefaultDataPermissionHandler implements DataPermissionHandler {
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否忽略权限控制,默认不忽略
|
||||
* <p>
|
||||
* 是否忽略权限控制
|
||||
* </p>
|
||||
* 若当前的 mappedStatementId 存在于 <Code>MappedStatementIdsWithoutDataScope<Code/>
|
||||
* 中,则表示无需处理
|
||||
* @param mappedStatementId Mapper方法ID
|
||||
* @return always false
|
||||
*/
|
||||
@Override
|
||||
public boolean ignorePermissionControl(String mappedStatementId) {
|
||||
return false;
|
||||
return MappedStatementIdsWithoutDataScope.contains(mappedStatementId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.hccake.ballcat.common.datascope.holder;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* DataScope 匹配数
|
||||
*
|
||||
* @author hccake
|
||||
*/
|
||||
public final class DataScopeMatchNumHolder {
|
||||
|
||||
private DataScopeMatchNumHolder() {
|
||||
}
|
||||
|
||||
private static ThreadLocal<AtomicInteger> matchNumTreadLocal;
|
||||
|
||||
public static void create() {
|
||||
matchNumTreadLocal = ThreadLocal.withInitial(AtomicInteger::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* get dataScope
|
||||
* @return dataScopes
|
||||
*/
|
||||
public static int getMatchNum() {
|
||||
AtomicInteger matchNum = matchNumTreadLocal.get();
|
||||
return matchNum.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加 dataScope
|
||||
*/
|
||||
public static void incrementMatchNum() {
|
||||
AtomicInteger matchNum = matchNumTreadLocal.get();
|
||||
matchNum.incrementAndGet();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除 dataScope
|
||||
*/
|
||||
public static void remove() {
|
||||
matchNumTreadLocal.remove();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.hccake.ballcat.common.datascope.holder;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 该类用于存储,不需数据权限处理的 mappedStatementId 集合
|
||||
*
|
||||
* @author hccake
|
||||
*/
|
||||
public class MappedStatementIdsWithoutDataScope {
|
||||
|
||||
private static final Set<String> MAPPED_STATEMENT_IDS = new HashSet<>();
|
||||
|
||||
public static void addStatementId(String mappedStatementId) {
|
||||
MAPPED_STATEMENT_IDS.add(mappedStatementId);
|
||||
}
|
||||
|
||||
public static boolean contains(String mappedStatementId) {
|
||||
return MAPPED_STATEMENT_IDS.contains(mappedStatementId);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,13 +2,19 @@ package com.hccake.ballcat.common.datascope.interceptor;
|
||||
|
||||
import com.hccake.ballcat.common.datascope.DataScope;
|
||||
import com.hccake.ballcat.common.datascope.handler.DataPermissionHandler;
|
||||
import com.hccake.ballcat.common.datascope.holder.DataScopeMatchNumHolder;
|
||||
import com.hccake.ballcat.common.datascope.holder.MappedStatementIdsWithoutDataScope;
|
||||
import com.hccake.ballcat.common.datascope.processor.DataScopeSqlProcessor;
|
||||
import com.hccake.ballcat.common.datascope.util.PluginUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.ibatis.executor.statement.StatementHandler;
|
||||
import org.apache.ibatis.mapping.MappedStatement;
|
||||
import org.apache.ibatis.mapping.SqlCommandType;
|
||||
import org.apache.ibatis.plugin.*;
|
||||
import org.apache.ibatis.plugin.Interceptor;
|
||||
import org.apache.ibatis.plugin.Intercepts;
|
||||
import org.apache.ibatis.plugin.Invocation;
|
||||
import org.apache.ibatis.plugin.Plugin;
|
||||
import org.apache.ibatis.plugin.Signature;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.List;
|
||||
@@ -49,6 +55,9 @@ public class DataPermissionInterceptor implements Interceptor {
|
||||
return invocation.proceed();
|
||||
}
|
||||
|
||||
try {
|
||||
// 创建 matchNumTreadLocal
|
||||
DataScopeMatchNumHolder.create();
|
||||
// 根据 DataScopes 进行数据权限的 sql 处理
|
||||
if (sct == SqlCommandType.SELECT) {
|
||||
mpBs.sql(dataScopeSqlProcessor.parserSingle(mpBs.sql(), dataScopes));
|
||||
@@ -56,6 +65,14 @@ public class DataPermissionInterceptor implements Interceptor {
|
||||
else if (sct == SqlCommandType.INSERT || sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) {
|
||||
mpBs.sql(dataScopeSqlProcessor.parserMulti(mpBs.sql(), dataScopes));
|
||||
}
|
||||
// 如果解析后发现当前 mappedStatementId 对应的 sql,没有任何数据权限匹配,则记录下来,后续可以直接跳过不解析
|
||||
if (DataScopeMatchNumHolder.getMatchNum() == 0) {
|
||||
MappedStatementIdsWithoutDataScope.addStatementId(mappedStatementId);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
DataScopeMatchNumHolder.remove();
|
||||
}
|
||||
|
||||
// 执行 sql
|
||||
return invocation.proceed();
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.hccake.ballcat.common.datascope.processor;
|
||||
|
||||
import com.hccake.ballcat.common.datascope.DataScope;
|
||||
import com.hccake.ballcat.common.datascope.holder.DataScopeHolder;
|
||||
import com.hccake.ballcat.common.datascope.holder.DataScopeMatchNumHolder;
|
||||
import com.hccake.ballcat.common.datascope.parser.JsqlParserSupport;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -34,12 +35,14 @@ import net.sf.jsqlparser.statement.select.SubSelect;
|
||||
import net.sf.jsqlparser.statement.select.ValuesList;
|
||||
import net.sf.jsqlparser.statement.select.WithItem;
|
||||
import net.sf.jsqlparser.statement.update.Update;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Deque;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 数据权限 sql 处理器 参考 mybatis-plus 租户拦截器,解析 sql where 部分,进行查询表达式注入
|
||||
@@ -351,8 +354,18 @@ public class DataScopeSqlProcessor extends JsqlParserSupport {
|
||||
// 获取表名
|
||||
String tableName = getTableName(table.getName());
|
||||
|
||||
List<DataScope> dataScopes = DataScopeHolder.get();
|
||||
Expression dataFilterExpression = dataScopes.stream().filter(x -> x.getTableNames().contains(tableName))
|
||||
// 进行 dataScope 的表名匹配
|
||||
List<DataScope> matchDataScopes = DataScopeHolder.get().stream()
|
||||
.filter(x -> x.getTableNames().contains(tableName)).collect(Collectors.toList());
|
||||
if (CollectionUtils.isEmpty(matchDataScopes)) {
|
||||
return currentExpression;
|
||||
}
|
||||
|
||||
// 匹配则计数
|
||||
DataScopeMatchNumHolder.incrementMatchNum();
|
||||
|
||||
// 获取到数据权限过滤的表达式
|
||||
Expression dataFilterExpression = matchDataScopes.stream()
|
||||
.map(x -> x.getExpression(tableName, table.getAlias())).filter(Objects::nonNull)
|
||||
.reduce(AndExpression::new).orElse(null);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user