Quellcode durchsuchen

feat: jsqlparser提供统一解析类,可配置解析函数,并加入缓存选项

miemie vor 1 Jahr
Ursprung
Commit
5dbcd66a78

+ 5 - 0
build.gradle

@@ -189,6 +189,11 @@ subprojects {
 //        exclude("**/generator/**")
     }
 
+    task cleanBuildDir(type: Delete) {
+        delete "${projectDir}/out"
+    }
+    tasks.clean.dependsOn(cleanBuildDir)
+
     task javadocJar(type: Jar) {
         archiveClassifier = 'javadoc'
         from javadoc

+ 1 - 0
changelog-temp.md

@@ -25,3 +25,4 @@ feat: 参数填充器支持多参数填充
 feat: BaseMapper新增selectMaps(page, wrapper)与selectList(page, wrapper)方法
 feat: 升级mybatis至3.5.13,mybatis-spring至2.1.1
 docs: 修正DdlHelper注释错误
+feat: jsqlparser提供统一解析类,可配置解析函数,并加入缓存选项

+ 3 - 0
mybatis-plus-extension/build.gradle

@@ -16,6 +16,9 @@ dependencies {
     implementation "${lib['mybatis-thymeleaf']}"
     implementation "${lib.'mybatis-velocity'}"
     implementation "${lib.'mybatis-freemarker'}"
+    implementation "de.ruedigermoeller:fst:2.57"
+    implementation "com.github.ben-manes.caffeine:caffeine:2.9.3"
     testImplementation "com.github.pagehelper:pagehelper:5.3.1"
     testImplementation "com.google.guava:guava:31.1-jre"
+    testImplementation "io.github.classgraph:classgraph:+"
 }

+ 13 - 0
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/parser/JsqlParserFunction.java

@@ -0,0 +1,13 @@
+package com.baomidou.mybatisplus.extension.parser;
+
+import net.sf.jsqlparser.JSQLParserException;
+
+/**
+ * @author miemie
+ * @since 2023-08-05
+ */
+@FunctionalInterface
+public interface JsqlParserFunction<T, R> {
+
+    R apply(T t) throws JSQLParserException;
+}

+ 45 - 0
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/parser/JsqlParserGlobal.java

@@ -0,0 +1,45 @@
+package com.baomidou.mybatisplus.extension.parser;
+
+import com.baomidou.mybatisplus.extension.parser.cache.JsqlParseCache;
+import lombok.Setter;
+import net.sf.jsqlparser.JSQLParserException;
+import net.sf.jsqlparser.parser.CCJSqlParserUtil;
+import net.sf.jsqlparser.statement.Statement;
+import net.sf.jsqlparser.statement.Statements;
+
+/**
+ * @author miemie
+ * @since 2023-08-05
+ */
+public class JsqlParserGlobal {
+    @Setter
+    private static JsqlParserFunction<String, Statement> parserSingleFunc = CCJSqlParserUtil::parse;
+    @Setter
+    private static JsqlParserFunction<String, Statements> parserMultiFunc = CCJSqlParserUtil::parseStatements;
+    @Setter
+    private static JsqlParseCache jsqlParseCache;
+
+    public static Statement parse(String sql) throws JSQLParserException {
+        if (jsqlParseCache == null) {
+            return parserSingleFunc.apply(sql);
+        }
+        Statement statement = jsqlParseCache.getStatement(sql);
+        if (statement == null) {
+            statement = parserSingleFunc.apply(sql);
+            jsqlParseCache.putStatement(sql, statement);
+        }
+        return statement;
+    }
+
+    public static Statements parseStatements(String sql) throws JSQLParserException {
+        if (jsqlParseCache == null) {
+            return parserMultiFunc.apply(sql);
+        }
+        Statements statements = jsqlParseCache.getStatements(sql);
+        if (statements == null) {
+            statements = parserMultiFunc.apply(sql);
+            jsqlParseCache.putStatements(sql, statements);
+        }
+        return statements;
+    }
+}

+ 2 - 3
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/parser/JsqlParserSupport.java

@@ -18,7 +18,6 @@ package com.baomidou.mybatisplus.extension.parser;
 import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
 import com.baomidou.mybatisplus.core.toolkit.StringPool;
 import net.sf.jsqlparser.JSQLParserException;
-import net.sf.jsqlparser.parser.CCJSqlParserUtil;
 import net.sf.jsqlparser.statement.Statement;
 import net.sf.jsqlparser.statement.Statements;
 import net.sf.jsqlparser.statement.delete.Delete;
@@ -46,7 +45,7 @@ public abstract class JsqlParserSupport {
             logger.debug("original SQL: " + sql);
         }
         try {
-            Statement statement = CCJSqlParserUtil.parse(sql);
+            Statement statement = JsqlParserGlobal.parse(sql);
             return processParser(statement, 0, sql, obj);
         } catch (JSQLParserException e) {
             throw ExceptionUtils.mpe("Failed to process, Error SQL: %s", e.getCause(), sql);
@@ -60,7 +59,7 @@ public abstract class JsqlParserSupport {
         try {
             // fixed github pull/295
             StringBuilder sb = new StringBuilder();
-            Statements statements = CCJSqlParserUtil.parseStatements(sql);
+            Statements statements = JsqlParserGlobal.parseStatements(sql);
             int i = 0;
             for (Statement statement : statements.getStatements()) {
                 if (i > 0) {

+ 243 - 0
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/parser/cache/FstFactory.java

@@ -0,0 +1,243 @@
+package com.baomidou.mybatisplus.extension.parser.cache;
+
+import org.nustaq.serialization.FSTConfiguration;
+
+/**
+ * @author miemie
+ * @since 2023-08-06
+ */
+public class FstFactory {
+    private static final FstFactory FACTORY = new FstFactory();
+    private final FSTConfiguration conf = FSTConfiguration.createDefaultConfiguration();
+
+    public static FstFactory getDefaultFactory() {
+        return FACTORY;
+    }
+
+    public FstFactory() {
+        conf.registerClass(net.sf.jsqlparser.expression.Alias.class);
+        conf.registerClass(net.sf.jsqlparser.expression.Alias.AliasColumn.class);
+        conf.registerClass(net.sf.jsqlparser.expression.AllValue.class);
+        conf.registerClass(net.sf.jsqlparser.expression.AnalyticExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.AnyComparisonExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.ArrayConstructor.class);
+        conf.registerClass(net.sf.jsqlparser.expression.ArrayExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.CaseExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.CastExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.CollateExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.ConnectByRootOperator.class);
+        conf.registerClass(net.sf.jsqlparser.expression.DateTimeLiteralExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.DateValue.class);
+        conf.registerClass(net.sf.jsqlparser.expression.DoubleValue.class);
+        conf.registerClass(net.sf.jsqlparser.expression.ExtractExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.FilterOverImpl.class);
+        conf.registerClass(net.sf.jsqlparser.expression.Function.class);
+        conf.registerClass(net.sf.jsqlparser.expression.HexValue.class);
+        conf.registerClass(net.sf.jsqlparser.expression.IntervalExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.JdbcNamedParameter.class);
+        conf.registerClass(net.sf.jsqlparser.expression.JdbcParameter.class);
+        conf.registerClass(net.sf.jsqlparser.expression.JsonAggregateFunction.class);
+        conf.registerClass(net.sf.jsqlparser.expression.JsonExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.JsonFunction.class);
+        conf.registerClass(net.sf.jsqlparser.expression.JsonFunctionExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.JsonKeyValuePair.class);
+        conf.registerClass(net.sf.jsqlparser.expression.KeepExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.LongValue.class);
+        conf.registerClass(net.sf.jsqlparser.expression.MySQLGroupConcat.class);
+        conf.registerClass(net.sf.jsqlparser.expression.MySQLIndexHint.class);
+        conf.registerClass(net.sf.jsqlparser.expression.NextValExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.NotExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.NullValue.class);
+        conf.registerClass(net.sf.jsqlparser.expression.NumericBind.class);
+        conf.registerClass(net.sf.jsqlparser.expression.OracleHierarchicalExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.OracleHint.class);
+        conf.registerClass(net.sf.jsqlparser.expression.OracleNamedFunctionParameter.class);
+        conf.registerClass(net.sf.jsqlparser.expression.OrderByClause.class);
+        conf.registerClass(net.sf.jsqlparser.expression.OverlapsCondition.class);
+        conf.registerClass(net.sf.jsqlparser.expression.Parenthesis.class);
+        conf.registerClass(net.sf.jsqlparser.expression.PartitionByClause.class);
+        conf.registerClass(net.sf.jsqlparser.expression.RowConstructor.class);
+        conf.registerClass(net.sf.jsqlparser.expression.RowGetExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.SQLServerHints.class);
+        conf.registerClass(net.sf.jsqlparser.expression.SafeCastExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.SignedExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.StringValue.class);
+        conf.registerClass(net.sf.jsqlparser.expression.TimeKeyExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.TimeValue.class);
+        conf.registerClass(net.sf.jsqlparser.expression.TimestampValue.class);
+        conf.registerClass(net.sf.jsqlparser.expression.TimezoneExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.TryCastExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.UserVariable.class);
+        conf.registerClass(net.sf.jsqlparser.expression.ValueListExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.VariableAssignment.class);
+        conf.registerClass(net.sf.jsqlparser.expression.WhenClause.class);
+        conf.registerClass(net.sf.jsqlparser.expression.WindowDefinition.class);
+        conf.registerClass(net.sf.jsqlparser.expression.WindowElement.class);
+        conf.registerClass(net.sf.jsqlparser.expression.WindowOffset.class);
+        conf.registerClass(net.sf.jsqlparser.expression.WindowRange.class);
+        conf.registerClass(net.sf.jsqlparser.expression.XMLSerializeExpr.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.arithmetic.Addition.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.arithmetic.BitwiseAnd.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.arithmetic.BitwiseLeftShift.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.arithmetic.BitwiseOr.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.arithmetic.BitwiseRightShift.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.arithmetic.BitwiseXor.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.arithmetic.Concat.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.arithmetic.Division.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.arithmetic.IntegerDivision.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.arithmetic.Modulo.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.arithmetic.Multiplication.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.arithmetic.Subtraction.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.conditional.AndExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.conditional.OrExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.conditional.XorExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.relational.Between.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.relational.EqualsTo.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.relational.ExistsExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.relational.ExpressionList.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.relational.FullTextSearch.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.relational.GeometryDistance.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.relational.GreaterThan.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.relational.GreaterThanEquals.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.relational.InExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.relational.IsBooleanExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.relational.IsDistinctExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.relational.IsNullExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.relational.JsonOperator.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.relational.LikeExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.relational.Matches.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.relational.MinorThan.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.relational.MinorThanEquals.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.relational.NotEqualsTo.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.relational.RegExpMatchOperator.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.relational.RegExpMySQLOperator.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.relational.SimilarToExpression.class);
+        conf.registerClass(net.sf.jsqlparser.parser.ASTNodeAccessImpl.class);
+        conf.registerClass(net.sf.jsqlparser.parser.Token.class);
+        conf.registerClass(net.sf.jsqlparser.schema.Column.class);
+        conf.registerClass(net.sf.jsqlparser.schema.Sequence.class);
+        conf.registerClass(net.sf.jsqlparser.schema.Synonym.class);
+        conf.registerClass(net.sf.jsqlparser.schema.Table.class);
+        conf.registerClass(net.sf.jsqlparser.statement.Block.class);
+        conf.registerClass(net.sf.jsqlparser.statement.Commit.class);
+        conf.registerClass(net.sf.jsqlparser.statement.DeclareStatement.class);
+        conf.registerClass(net.sf.jsqlparser.statement.DeclareStatement.TypeDefExpr.class);
+        conf.registerClass(net.sf.jsqlparser.statement.DescribeStatement.class);
+        conf.registerClass(net.sf.jsqlparser.statement.ExplainStatement.class);
+        conf.registerClass(net.sf.jsqlparser.statement.ExplainStatement.Option.class);
+        conf.registerClass(net.sf.jsqlparser.statement.IfElseStatement.class);
+        conf.registerClass(net.sf.jsqlparser.statement.OutputClause.class);
+        conf.registerClass(net.sf.jsqlparser.statement.PurgeStatement.class);
+        conf.registerClass(net.sf.jsqlparser.statement.ReferentialAction.class);
+        conf.registerClass(net.sf.jsqlparser.statement.ResetStatement.class);
+        conf.registerClass(net.sf.jsqlparser.statement.RollbackStatement.class);
+        conf.registerClass(net.sf.jsqlparser.statement.SavepointStatement.class);
+        conf.registerClass(net.sf.jsqlparser.statement.SetStatement.class);
+        conf.registerClass(net.sf.jsqlparser.statement.ShowColumnsStatement.class);
+        conf.registerClass(net.sf.jsqlparser.statement.ShowStatement.class);
+        conf.registerClass(net.sf.jsqlparser.statement.Statements.class);
+        conf.registerClass(net.sf.jsqlparser.statement.UnsupportedStatement.class);
+        conf.registerClass(net.sf.jsqlparser.statement.UseStatement.class);
+        conf.registerClass(net.sf.jsqlparser.statement.alter.Alter.class);
+        conf.registerClass(net.sf.jsqlparser.statement.alter.AlterExpression.class);
+        conf.registerClass(net.sf.jsqlparser.statement.alter.AlterExpression.ColumnDataType.class);
+        conf.registerClass(net.sf.jsqlparser.statement.alter.AlterExpression.ColumnDropDefault.class);
+        conf.registerClass(net.sf.jsqlparser.statement.alter.AlterExpression.ColumnDropNotNull.class);
+        conf.registerClass(net.sf.jsqlparser.statement.alter.AlterSession.class);
+        conf.registerClass(net.sf.jsqlparser.statement.alter.AlterSystemStatement.class);
+        conf.registerClass(net.sf.jsqlparser.statement.alter.RenameTableStatement.class);
+        conf.registerClass(net.sf.jsqlparser.statement.alter.sequence.AlterSequence.class);
+        conf.registerClass(net.sf.jsqlparser.statement.analyze.Analyze.class);
+        conf.registerClass(net.sf.jsqlparser.statement.comment.Comment.class);
+        conf.registerClass(net.sf.jsqlparser.statement.create.function.CreateFunction.class);
+        conf.registerClass(net.sf.jsqlparser.statement.create.index.CreateIndex.class);
+        conf.registerClass(net.sf.jsqlparser.statement.create.procedure.CreateProcedure.class);
+        conf.registerClass(net.sf.jsqlparser.statement.create.schema.CreateSchema.class);
+        conf.registerClass(net.sf.jsqlparser.statement.create.sequence.CreateSequence.class);
+        conf.registerClass(net.sf.jsqlparser.statement.create.synonym.CreateSynonym.class);
+        conf.registerClass(net.sf.jsqlparser.statement.create.table.CheckConstraint.class);
+        conf.registerClass(net.sf.jsqlparser.statement.create.table.ColDataType.class);
+        conf.registerClass(net.sf.jsqlparser.statement.create.table.ColumnDefinition.class);
+        conf.registerClass(net.sf.jsqlparser.statement.create.table.CreateTable.class);
+        conf.registerClass(net.sf.jsqlparser.statement.create.table.ExcludeConstraint.class);
+        conf.registerClass(net.sf.jsqlparser.statement.create.table.ForeignKeyIndex.class);
+        conf.registerClass(net.sf.jsqlparser.statement.create.table.Index.class);
+        conf.registerClass(net.sf.jsqlparser.statement.create.table.Index.ColumnParams.class);
+        conf.registerClass(net.sf.jsqlparser.statement.create.table.NamedConstraint.class);
+        conf.registerClass(net.sf.jsqlparser.statement.create.table.RowMovement.class);
+        conf.registerClass(net.sf.jsqlparser.statement.create.view.AlterView.class);
+        conf.registerClass(net.sf.jsqlparser.statement.create.view.CreateView.class);
+        conf.registerClass(net.sf.jsqlparser.statement.delete.Delete.class);
+        conf.registerClass(net.sf.jsqlparser.statement.drop.Drop.class);
+        conf.registerClass(net.sf.jsqlparser.statement.execute.Execute.class);
+        conf.registerClass(net.sf.jsqlparser.statement.grant.Grant.class);
+        conf.registerClass(net.sf.jsqlparser.statement.insert.Insert.class);
+        conf.registerClass(net.sf.jsqlparser.statement.insert.InsertConflictAction.class);
+        conf.registerClass(net.sf.jsqlparser.statement.insert.InsertConflictTarget.class);
+        conf.registerClass(net.sf.jsqlparser.statement.merge.Merge.class);
+        conf.registerClass(net.sf.jsqlparser.statement.merge.MergeInsert.class);
+        conf.registerClass(net.sf.jsqlparser.statement.merge.MergeUpdate.class);
+        conf.registerClass(net.sf.jsqlparser.statement.replace.Replace.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.AllColumns.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.AllTableColumns.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.Distinct.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.ExceptOp.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.ExpressionListItem.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.Fetch.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.First.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.FunctionItem.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.GroupByElement.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.IntersectOp.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.Join.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.KSQLJoinWindow.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.KSQLWindow.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.LateralSubSelect.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.Limit.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.MinusOp.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.Offset.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.OptimizeFor.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.OrderByElement.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.ParenthesisFromItem.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.Pivot.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.PivotXml.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.PlainSelect.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.Select.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.SelectExpressionItem.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.SetOperationList.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.Skip.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.SubJoin.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.SubSelect.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.TableFunction.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.Top.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.UnPivot.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.UnionOp.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.ValuesList.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.Wait.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.WithIsolation.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.WithItem.class);
+        conf.registerClass(net.sf.jsqlparser.statement.show.ShowIndexStatement.class);
+        conf.registerClass(net.sf.jsqlparser.statement.show.ShowTablesStatement.class);
+        conf.registerClass(net.sf.jsqlparser.statement.truncate.Truncate.class);
+        conf.registerClass(net.sf.jsqlparser.statement.update.Update.class);
+        conf.registerClass(net.sf.jsqlparser.statement.update.UpdateSet.class);
+        conf.registerClass(net.sf.jsqlparser.statement.upsert.Upsert.class);
+        conf.registerClass(net.sf.jsqlparser.statement.values.ValuesStatement.class);
+        conf.registerClass(net.sf.jsqlparser.util.cnfexpression.MultiAndExpression.class);
+        conf.registerClass(net.sf.jsqlparser.util.cnfexpression.MultiOrExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.BinaryExpression.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.relational.ComparisonOperator.class);
+        conf.registerClass(net.sf.jsqlparser.expression.operators.relational.OldOracleJoinBinaryExpression.class);
+        conf.registerClass(net.sf.jsqlparser.statement.CreateFunctionalStatement.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.SetOperation.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.SpecialSubSelect.class);
+        conf.registerClass(net.sf.jsqlparser.util.cnfexpression.MultipleExpression.class);
+    }
+
+    public byte[] asByteArray(Object obj) {
+        return conf.asByteArray(obj);
+    }
+
+    public Object asObject(byte[] bytes) {
+        return conf.asObject(bytes);
+    }
+}

+ 88 - 0
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/parser/cache/FstSerialCaffeineJsqlParseCache.java

@@ -0,0 +1,88 @@
+package com.baomidou.mybatisplus.extension.parser.cache;
+
+import com.github.benmanes.caffeine.cache.Cache;
+import com.github.benmanes.caffeine.cache.Caffeine;
+import lombok.Setter;
+import net.sf.jsqlparser.statement.Statement;
+import net.sf.jsqlparser.statement.Statements;
+import org.apache.ibatis.logging.Log;
+import org.apache.ibatis.logging.LogFactory;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+/**
+ * @author miemie
+ * @since 2023-08-05
+ */
+public class FstSerialCaffeineJsqlParseCache implements JsqlParseCache {
+    protected final Log logger = LogFactory.getLog(this.getClass());
+    private final Cache<String, byte[]> cache;
+    @Setter
+    private boolean async = false;
+    @Setter
+    private Executor executor;
+
+    public FstSerialCaffeineJsqlParseCache(Cache<String, byte[]> cache) {
+        this.cache = cache;
+    }
+
+    public FstSerialCaffeineJsqlParseCache(Consumer<Caffeine<Object, Object>> consumer) {
+        Caffeine<Object, Object> caffeine = Caffeine.newBuilder();
+        consumer.accept(caffeine);
+        this.cache = caffeine.build();
+    }
+
+    @Override
+    public void putStatement(String sql, Statement value) {
+        put(sql, value);
+    }
+
+    @Override
+    public void putStatements(String sql, Statements value) {
+        put(sql, value);
+    }
+
+    protected void put(String sql, Object value) {
+        if (async) {
+            if (executor != null) {
+                CompletableFuture.runAsync(() -> cache.put(sql, serialize(value)), executor);
+            } else {
+                CompletableFuture.runAsync(() -> cache.put(sql, serialize(value)));
+            }
+        } else {
+            cache.put(sql, serialize(value));
+        }
+    }
+
+    @Override
+    public Statement getStatement(String sql) {
+        byte[] bytes = cache.getIfPresent(sql);
+        if (bytes != null)
+            return (Statement) deserialize(sql, bytes);
+        return null;
+    }
+
+    @Override
+    public Statements getStatements(String sql) {
+        byte[] bytes = cache.getIfPresent(sql);
+        if (bytes != null)
+            return (Statements) deserialize(sql, bytes);
+        return null;
+    }
+
+    protected byte[] serialize(Object obj) {
+        return FstFactory.getDefaultFactory().asByteArray(obj);
+    }
+
+    protected Object deserialize(String sql, byte[] bytes) {
+        try {
+            return FstFactory.getDefaultFactory().asObject(bytes);
+        } catch (Exception e) {
+            cache.invalidate(sql);
+            logger.error("deserialize error", e);
+        }
+        return null;
+    }
+}

+ 89 - 0
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/parser/cache/JdkSerialCaffeineJsqlParseCache.java

@@ -0,0 +1,89 @@
+package com.baomidou.mybatisplus.extension.parser.cache;
+
+import com.baomidou.mybatisplus.core.toolkit.SerializationUtils;
+import com.github.benmanes.caffeine.cache.Cache;
+import com.github.benmanes.caffeine.cache.Caffeine;
+import lombok.Setter;
+import net.sf.jsqlparser.statement.Statement;
+import net.sf.jsqlparser.statement.Statements;
+import org.apache.ibatis.logging.Log;
+import org.apache.ibatis.logging.LogFactory;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+/**
+ * @author miemie
+ * @since 2023-08-05
+ */
+public class JdkSerialCaffeineJsqlParseCache implements JsqlParseCache {
+    protected final Log logger = LogFactory.getLog(this.getClass());
+    private final Cache<String, byte[]> cache;
+    @Setter
+    private boolean async = false;
+    @Setter
+    private Executor executor;
+
+    public JdkSerialCaffeineJsqlParseCache(Cache<String, byte[]> cache) {
+        this.cache = cache;
+    }
+
+    public JdkSerialCaffeineJsqlParseCache(Consumer<Caffeine<Object, Object>> consumer) {
+        Caffeine<Object, Object> caffeine = Caffeine.newBuilder();
+        consumer.accept(caffeine);
+        this.cache = caffeine.build();
+    }
+
+    @Override
+    public void putStatement(String sql, Statement value) {
+        put(sql, value);
+    }
+
+    @Override
+    public void putStatements(String sql, Statements value) {
+        put(sql, value);
+    }
+
+    protected void put(String sql, Object value) {
+        if (async) {
+            if (executor != null) {
+                CompletableFuture.runAsync(() -> cache.put(sql, serialize(value)), executor);
+            } else {
+                CompletableFuture.runAsync(() -> cache.put(sql, serialize(value)));
+            }
+        } else {
+            cache.put(sql, serialize(value));
+        }
+    }
+
+    @Override
+    public Statement getStatement(String sql) {
+        byte[] bytes = cache.getIfPresent(sql);
+        if (bytes != null)
+            return (Statement) deserialize(sql, bytes);
+        return null;
+    }
+
+    @Override
+    public Statements getStatements(String sql) {
+        byte[] bytes = cache.getIfPresent(sql);
+        if (bytes != null)
+            return (Statements) deserialize(sql, bytes);
+        return null;
+    }
+
+    protected byte[] serialize(Object obj) {
+        return SerializationUtils.serialize(obj);
+    }
+
+    protected Object deserialize(String sql, byte[] bytes) {
+        try {
+            return SerializationUtils.deserialize(bytes);
+        } catch (Exception e) {
+            cache.invalidate(sql);
+            logger.error("deserialize error", e);
+        }
+        return null;
+    }
+}

+ 19 - 0
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/parser/cache/JsqlParseCache.java

@@ -0,0 +1,19 @@
+package com.baomidou.mybatisplus.extension.parser.cache;
+
+import net.sf.jsqlparser.statement.Statement;
+import net.sf.jsqlparser.statement.Statements;
+
+/**
+ * @author miemie
+ * @since 2023-08-05
+ */
+public interface JsqlParseCache {
+
+    void putStatement(String sql, Statement value);
+
+    void putStatements(String sql, Statements value);
+
+    Statement getStatement(String sql);
+
+    Statements getStatements(String sql);
+}

+ 90 - 0
mybatis-plus-extension/src/test/java/com/baomidou/mybatisplus/extension/parser/JsqlParserSimpleSerialTest.java

@@ -0,0 +1,90 @@
+package com.baomidou.mybatisplus.extension.parser;
+
+import com.baomidou.mybatisplus.extension.parser.cache.FstFactory;
+import net.sf.jsqlparser.JSQLParserException;
+import net.sf.jsqlparser.parser.CCJSqlParserUtil;
+import net.sf.jsqlparser.statement.Statement;
+import org.junit.jupiter.api.Test;
+import org.springframework.util.SerializationUtils;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * @author miemie
+ * @since 2023-08-03
+ */
+class JsqlParserSimpleSerialTest {
+    private final static int len = 1000;
+    private final static String sql = "SELECT * FROM entity e " +
+            "LEFT JOIN entity1 e1 " +
+            "LEFT JOIN entity2 e2 ON e2.id = e1.id " +
+            "ON e1.id = e.id " +
+            "WHERE (e.id = ? OR e.NAME = ?)";
+
+    @Test
+    void test() throws JSQLParserException {
+        System.out.println("循环次数: " + len);
+        noSerial();
+        jdkSerial();
+        fstSerial();
+    }
+
+    void noSerial() throws JSQLParserException {
+        long startTime = System.currentTimeMillis();
+        for (int i = 0; i < len; i++) {
+            CCJSqlParserUtil.parse(sql);
+        }
+        long endTime = System.currentTimeMillis();
+        long e1 = endTime - startTime;
+        System.out.printf("普通解析执行耗时: %s 毫秒, 均耗时: %s%n", e1, (double) e1 / len);
+    }
+
+    void jdkSerial() throws JSQLParserException {
+        Statement statement = CCJSqlParserUtil.parse(sql);
+        String target = statement.toString();
+        byte[] serial = null;
+        long startTime = System.currentTimeMillis();
+        for (int i = 0; i < len; i++) {
+            serial = SerializationUtils.serialize(statement);
+        }
+        long endTime = System.currentTimeMillis();
+        long et = endTime - startTime;
+        System.out.printf("jdk serialize 执行耗时: %s 毫秒,byte大小: %s, 均耗时: %s%n", et, serial.length, (double) et / len);
+
+
+        startTime = System.currentTimeMillis();
+        for (int i = 0; i < len; i++) {
+            statement = (Statement) SerializationUtils.deserialize(serial);
+        }
+        endTime = System.currentTimeMillis();
+        et = endTime - startTime;
+        System.out.printf("jdk deserialize 执行耗时: %s 毫秒, 均耗时: %s%n", et, (double) et / len);
+        assertThat(statement).isNotNull();
+        assertThat(statement.toString()).isEqualTo(target);
+    }
+
+    void fstSerial() throws JSQLParserException {
+        Statement statement = CCJSqlParserUtil.parse(sql);
+        String target = statement.toString();
+        FstFactory factory = FstFactory.getDefaultFactory();
+        byte[] serial = null;
+        long startTime = System.currentTimeMillis();
+        for (int i = 0; i < len; i++) {
+            serial = factory.asByteArray(statement);
+        }
+        long endTime = System.currentTimeMillis();
+        long et = endTime - startTime;
+        System.out.printf("fst serialize 执行耗时: %s 毫秒,byte大小: %s, 均耗时: %s%n", et, serial.length, (double) et / len);
+
+
+        startTime = System.currentTimeMillis();
+        for (int i = 0; i < len; i++) {
+            statement = (Statement) factory.asObject(serial);
+        }
+        endTime = System.currentTimeMillis();
+        et = endTime - startTime;
+        System.out.printf("fst deserialize 执行耗时: %s 毫秒, 均耗时: %s%n", et, (double) et / len);
+        assertThat(statement).isNotNull();
+        assertThat(statement.toString()).isEqualTo(target);
+    }
+}

+ 37 - 0
mybatis-plus-extension/src/test/java/com/baomidou/mybatisplus/extension/parser/cache/FstFactoryTest.java

@@ -0,0 +1,37 @@
+package com.baomidou.mybatisplus.extension.parser.cache;
+
+import io.github.classgraph.ClassGraph;
+import io.github.classgraph.ClassInfo;
+import io.github.classgraph.ScanResult;
+import org.junit.jupiter.api.Test;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author miemie
+ * @since 2023-08-06
+ */
+class FstFactoryTest {
+
+    @Test
+    void clazz() {
+        List<ClassInfo> list = new ArrayList<>();
+        List<ClassInfo> absList = new ArrayList<>();
+        try (ScanResult scanResult = new ClassGraph().enableClassInfo().acceptPackages("net.sf.jsqlparser").scan()) {
+            for (ClassInfo classInfo : scanResult.getAllClasses()) {
+                if (!classInfo.isInterface() && classInfo.implementsInterface(Serializable.class)) {
+                    if (classInfo.isAbstract()) {
+                        absList.add(classInfo);
+                        continue;
+                    }
+                    list.add(classInfo);
+                }
+            }
+        }
+        list.forEach(i -> System.out.printf("conf.registerClass(%s.class);%n", i.getName().replace("$", ".")));
+        System.out.println("↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓");
+        absList.forEach(i -> System.out.printf("conf.registerClass(%s.class);%n", i.getName().replace("$", ".")));
+    }
+}