瀏覽代碼

feat: #6687 多租户插件的查询使用索引的优化:多租户插件:增加配置项expressionAppendMode(默认true表示追加),设置false可以插入到最前方

yuxiaobin 2 月之前
父節點
當前提交
778de65bb3

+ 24 - 4
mybatis-plus-jsqlparser-support/mybatis-plus-jsqlparser-4.9/src/main/java/com/baomidou/mybatisplus/extension/plugins/inner/BaseMultiTableInnerInterceptor.java

@@ -47,6 +47,11 @@ import java.util.stream.Collectors;
 @SuppressWarnings({"rawtypes"})
 public abstract class BaseMultiTableInnerInterceptor extends JsqlParserSupport implements InnerInterceptor {
 
+    /**
+     * 条件表达式追加模式:true表示是后面追加(条件放最后),false表示插入到第一个位置(条件放第一个)
+     */
+    private boolean expressionAppendMode = true;
+
     protected void processSelectBody(Select selectBody, final String whereSegment) {
         if (selectBody == null) {
             return;
@@ -76,14 +81,29 @@ public abstract class BaseMultiTableInnerInterceptor extends JsqlParserSupport i
         }
         if (where != null) {
             if (where instanceof OrExpression) {
-                return new AndExpression(new Parenthesis(where), expression);
+                return appendExpression(new Parenthesis(where), expression);
             } else {
-                return new AndExpression(where, expression);
+                return appendExpression(where, expression);
             }
         }
         return expression;
     }
 
+    /**
+     * 追加表达式,默认追加到后面,可以配置变量 {@link #expressionAppendMode} 来控制追加到前面还是后面
+     *
+     * @param currentExpression 原sql的条件表达式
+     * @param injectExpression  注入的表达式
+     * @return 追加了条件的完整表达式(where条件 / on条件)
+     */
+    protected Expression appendExpression(Expression currentExpression, Expression injectExpression) {
+        if (expressionAppendMode) {
+            return new AndExpression(currentExpression, injectExpression);
+        } else {
+            return new AndExpression(injectExpression, currentExpression);
+        }
+    }
+
     /**
      * 处理 PlainSelect
      */
@@ -403,9 +423,9 @@ public abstract class BaseMultiTableInnerInterceptor extends JsqlParserSupport i
             return injectExpression;
         }
         if (currentExpression instanceof OrExpression) {
-            return new AndExpression(new Parenthesis(currentExpression), injectExpression);
+            return appendExpression(new Parenthesis(currentExpression), injectExpression);
         } else {
-            return new AndExpression(currentExpression, injectExpression);
+            return appendExpression(currentExpression, injectExpression);
         }
     }
 

+ 26 - 6
mybatis-plus-jsqlparser-support/mybatis-plus-jsqlparser-5.0/src/main/java/com/baomidou/mybatisplus/extension/plugins/inner/BaseMultiTableInnerInterceptor.java

@@ -48,6 +48,11 @@ import java.util.stream.Collectors;
 @SuppressWarnings({"rawtypes"})
 public abstract class BaseMultiTableInnerInterceptor extends JsqlParserSupport implements InnerInterceptor {
 
+    /**
+     * 条件表达式追加模式:true表示是后面追加(条件放最后),false表示插入到第一个位置(条件放第一个)
+     */
+    private boolean expressionAppendMode = true;
+
     protected void processSelectBody(Select selectBody, final String whereSegment) {
         if (selectBody == null) {
             return;
@@ -77,9 +82,9 @@ public abstract class BaseMultiTableInnerInterceptor extends JsqlParserSupport i
         }
         if (where != null) {
             if (where instanceof OrExpression) {
-                return new AndExpression(new ParenthesedExpressionList<>(where), expression);
+                return appendExpression(new ParenthesedExpressionList<>(where), expression);
             } else {
-                return new AndExpression(where, expression);
+                return appendExpression(where, expression);
             }
         }
         return expression;
@@ -382,9 +387,9 @@ public abstract class BaseMultiTableInnerInterceptor extends JsqlParserSupport i
         }
         // 构造每张表的条件
         List<Expression> expressions = tables.stream()
-                .map(item -> buildTableExpression(item, currentExpression, whereSegment))
-                .filter(Objects::nonNull)
-                .collect(Collectors.toList());
+            .map(item -> buildTableExpression(item, currentExpression, whereSegment))
+            .filter(Objects::nonNull)
+            .collect(Collectors.toList());
 
         // 没有表需要处理直接返回
         if (CollectionUtils.isEmpty(expressions)) {
@@ -404,9 +409,24 @@ public abstract class BaseMultiTableInnerInterceptor extends JsqlParserSupport i
             return injectExpression;
         }
         if (currentExpression instanceof OrExpression) {
-            return new AndExpression(new ParenthesedExpressionList<>(currentExpression), injectExpression);
+            return appendExpression(new ParenthesedExpressionList<>(currentExpression), injectExpression);
         } else {
+            return appendExpression(currentExpression, injectExpression);
+        }
+    }
+
+    /**
+     * 追加表达式,默认追加到后面,可以配置变量 {@link #expressionAppendMode} 来控制追加到前面还是后面
+     *
+     * @param currentExpression 原sql的条件表达式
+     * @param injectExpression  注入的表达式
+     * @return 追加了条件的完整表达式(where条件 / on条件)
+     */
+    protected Expression appendExpression(Expression currentExpression, Expression injectExpression) {
+        if (expressionAppendMode) {
             return new AndExpression(currentExpression, injectExpression);
+        } else {
+            return new AndExpression(injectExpression, currentExpression);
         }
     }
 

+ 81 - 0
mybatis-plus-jsqlparser-support/mybatis-plus-jsqlparser-5.0/src/test/java/com/baomidou/mybatisplus/test/extension/plugins/inner/TenantLineInnerInterceptorTest.java

@@ -4,6 +4,8 @@ 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;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -31,6 +33,28 @@ class TenantLineInnerInterceptorTest {
         }
     });
 
+    private final TenantLineInnerInterceptor interceptor2 = new TenantLineInnerInterceptor(new TenantLineHandler() {
+        private boolean ignoreFirst;// 需要执行 getTenantId 前必须先执行 ignoreTable
+
+        @Override
+        public Expression getTenantId() {
+            assertThat(ignoreFirst).isEqualTo(true);
+            ignoreFirst = false;
+            return new LongValue(1);
+        }
+
+        @Override
+        public boolean ignoreTable(String tableName) {
+            ignoreFirst = true;
+            return tableName.startsWith("with_as");
+        }
+    });
+
+    @BeforeEach
+    void init() {
+        interceptor2.setExpressionAppendMode(false);
+    }
+
     @Test
     void insert() {
         // plain
@@ -65,6 +89,59 @@ class TenantLineInnerInterceptorTest {
         assertSql("insert into entity (id,name) select t.* from (select id,name from entity3 e3) t",
             "INSERT INTO entity (id, name, tenant_id) SELECT t.* FROM (SELECT id, name, tenant_id FROM entity3 e3 WHERE e3.tenant_id = 1) t");
     }
+    @Test
+    void crud2() {
+        assertSql2("select * from entity where id = ?",
+            "SELECT * FROM entity WHERE tenant_id = 1 AND id = ?");
+
+        assertSql2("select * from entity where id = ? or name = ?",
+            "SELECT * FROM entity WHERE tenant_id = 1 AND (id = ? OR name = ?)");
+
+        assertSql2("SELECT * FROM entity WHERE (id = ? OR name = ?)",
+            "SELECT * FROM entity WHERE tenant_id = 1 AND (id = ? OR name = ?)");
+
+        /* not */
+        assertSql2("SELECT * FROM entity WHERE not (id = ? OR name = ?)",
+            "SELECT * FROM entity WHERE tenant_id = 1 AND NOT (id = ? OR name = ?)");
+
+        assertSql2("SELECT * FROM entity u WHERE not (u.id = ? OR u.name = ?)",
+            "SELECT * FROM entity u WHERE u.tenant_id = 1 AND NOT (u.id = ? OR u.name = ?)");
+
+        //leftjoin
+        assertSql2("SELECT * FROM entity e " +
+                "left join entity1 e1 on e1.id = e.id " +
+                "WHERE e.id = ? OR e.name = ?",
+            "SELECT * FROM entity e " +
+                "LEFT JOIN entity1 e1 ON e1.tenant_id = 1 AND e1.id = e.id " +
+                "WHERE e.tenant_id = 1 AND (e.id = ? OR e.name = ?)");
+
+
+
+        assertSql2("SELECT * FROM entity e WHERE e.id IN (select e1.id from entity1 e1 where e1.id = ?)",
+            "SELECT * FROM entity e WHERE e.tenant_id = 1 AND e.id IN (SELECT e1.id FROM entity1 e1 WHERE e1.tenant_id = 1 AND e1.id = ?)");
+        // 在最前
+        assertSql2("SELECT * FROM entity e WHERE e.id IN " +
+                "(select e1.id from entity1 e1 where e1.id = ?) and e.id = ?",
+            "SELECT * FROM entity e WHERE e.tenant_id = 1 AND e.id IN " +
+                "(SELECT e1.id FROM entity1 e1 WHERE e1.tenant_id = 1 AND e1.id = ?) AND e.id = ?");
+        // 在最后
+        assertSql2("SELECT * FROM entity e WHERE e.id = ? and e.id IN " +
+                "(select e1.id from entity1 e1 where e1.id = ?)",
+            "SELECT * FROM entity e WHERE e.tenant_id = 1 AND e.id = ? AND e.id IN " +
+                "(SELECT e1.id FROM entity1 e1 WHERE e1.tenant_id = 1 AND e1.id = ?)");
+        // 在中间
+        assertSql2("SELECT * FROM entity e WHERE e.id = ? and e.id IN " +
+                "(select e1.id from entity1 e1 where e1.id = ?) and e.id = ?",
+            "SELECT * FROM entity e WHERE e.tenant_id = 1 AND e.id = ? AND e.id IN " +
+                "(SELECT e1.id FROM entity1 e1 WHERE e1.tenant_id = 1 AND e1.id = ?) AND e.id = ?");
+
+        /* EXISTS */
+        assertSql2("SELECT * FROM entity e WHERE EXISTS (select e1.id from entity1 e1 where e1.id = ?)",
+            "SELECT * FROM entity e WHERE e.tenant_id = 1 AND EXISTS (SELECT e1.id FROM entity1 e1 WHERE e1.tenant_id = 1 AND e1.id = ?)");
+
+        assertSql2("SELECT EXISTS (SELECT 1 FROM entity1 e WHERE e.id = ? LIMIT 1)","SELECT EXISTS (SELECT 1 FROM entity1 e WHERE e.tenant_id = 1 AND e.id = ? LIMIT 1)");
+
+    }
 
     @Test
     void delete() {
@@ -467,4 +544,8 @@ class TenantLineInnerInterceptorTest {
     void assertSql(String sql, String targetSql) {
         assertThat(interceptor.parserSingle(sql, null)).isEqualTo(targetSql);
     }
+
+    void assertSql2(String sql, String targetSql) {
+        assertThat(interceptor2.parserSingle(sql, null)).isEqualTo(targetSql);
+    }
 }

+ 23 - 3
mybatis-plus-jsqlparser-support/mybatis-plus-jsqlparser/src/main/java/com/baomidou/mybatisplus/extension/plugins/inner/BaseMultiTableInnerInterceptor.java

@@ -48,6 +48,11 @@ import java.util.stream.Collectors;
 @SuppressWarnings({"rawtypes"})
 public abstract class BaseMultiTableInnerInterceptor extends JsqlParserSupport implements InnerInterceptor {
 
+    /**
+     * 条件表达式追加模式:true表示是后面追加(条件放最后),false表示插入到第一个位置(条件放第一个)
+     */
+    private boolean expressionAppendMode = true;
+
     protected void processSelectBody(Select selectBody, final String whereSegment) {
         if (selectBody == null) {
             return;
@@ -77,9 +82,9 @@ public abstract class BaseMultiTableInnerInterceptor extends JsqlParserSupport i
         }
         if (where != null) {
             if (where instanceof OrExpression) {
-                return new AndExpression(new ParenthesedExpressionList<>(where), expression);
+                return appendExpression(new ParenthesedExpressionList<>(where), expression);
             } else {
-                return new AndExpression(where, expression);
+                return appendExpression(where, expression);
             }
         }
         return expression;
@@ -403,9 +408,24 @@ public abstract class BaseMultiTableInnerInterceptor extends JsqlParserSupport i
             return injectExpression;
         }
         if (currentExpression instanceof OrExpression) {
-            return new AndExpression(new ParenthesedExpressionList<>(currentExpression), injectExpression);
+            return appendExpression(new ParenthesedExpressionList<>(currentExpression), injectExpression);
         } else {
+            return appendExpression(currentExpression, injectExpression);
+        }
+    }
+
+    /**
+     * 追加表达式,默认追加到后面,可以配置变量 {@link #expressionAppendMode} 来控制追加到前面还是后面
+     *
+     * @param currentExpression 原sql的条件表达式
+     * @param injectExpression  注入的表达式
+     * @return 追加了条件的完整表达式(where条件 / on条件)
+     */
+    protected Expression appendExpression(Expression currentExpression, Expression injectExpression) {
+        if (expressionAppendMode) {
             return new AndExpression(currentExpression, injectExpression);
+        } else {
+            return new AndExpression(injectExpression, currentExpression);
         }
     }