12 Commits 3e0029a455 ... a97c845c01

Tác giả SHA1 Thông báo Ngày
  聂秋荣 a97c845c01 发布3.5.13-SNAPSHOT. 7 tháng trước cách đây
  聂秋荣 33119e5f8b 解决容器初始化时机问题导致的容器上下文对象为空(待优化). 7 tháng trước cách đây
  聂秋荣 764ce9c15d 升级jsqlparser5.2 7 tháng trước cách đây
  聂秋荣 908354d869 发布3.5.12 7 tháng trước cách đây
  miemieYaho 88d923213e Merge pull request #6777 from anyangdp/3.0 8 tháng trước cách đây
  anyangdp bcb48be2f6 Update JdbcUtils.java 8 tháng trước cách đây
  nieqiurong 7a2097850a 调整表索引信息获取. 8 tháng trước cách đây
  nieqiurong 15685ad653 调整解析线程池关闭处理. 8 tháng trước cách đây
  nieqiurong 79e0427aab 调整CompatibleSet.getInputStream方法为默认方法. 8 tháng trước cách đây
  nieqiurong ebe329ac2f 调整SPI实现(新增getProxyTargetObject()方法获取真实代理). 8 tháng trước cách đây
  nieqiurong b2082354c6 增加Db对多数据源的支持. 8 tháng trước cách đây
  nieqiurong 90b6587d0a 优化MapperProxy属性访问. 8 tháng trước cách đây
28 tập tin đã thay đổi với 543 bổ sung89 xóa
  1. 24 0
      CHANGELOG.md
  2. 2 16
      changelog-temp.md
  3. 1 1
      gradle.properties
  4. 18 18
      mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/mapper/BaseMapper.java
  5. 62 0
      mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/metadata/MapperProxyMetadata.java
  6. 3 2
      mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/override/MybatisMapperProxy.java
  7. 79 0
      mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/spi/CompatibleHelper.java
  8. 75 0
      mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/spi/CompatibleSet.java
  9. 64 10
      mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/MybatisUtils.java
  10. 4 0
      mybatis-plus-core/src/test/java/com/baomidou/mybatisplus/core/toolkit/MybatisUtilsTest.java
  11. 1 1
      mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/activerecord/AbstractModel.java
  12. 5 5
      mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/repository/AbstractRepository.java
  13. 4 0
      mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/spi/CompatibleHelper.java
  14. 5 20
      mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/spi/CompatibleSet.java
  15. 1 1
      mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/toolkit/JdbcUtils.java
  16. 9 1
      mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/toolkit/SqlHelper.java
  17. 10 7
      mybatis-plus-generator/src/main/java/com/baomidou/mybatisplus/generator/jdbc/DatabaseMetaDataWrapper.java
  18. 15 0
      mybatis-plus-jsqlparser-support/mybatis-plus-jsqlparser-4.9/src/main/java/com/baomidou/mybatisplus/extension/parser/JsqlParserGlobal.java
  19. 14 0
      mybatis-plus-jsqlparser-support/mybatis-plus-jsqlparser-5.0/src/main/java/com/baomidou/mybatisplus/extension/parser/JsqlParserGlobal.java
  20. 2 4
      mybatis-plus-jsqlparser-support/mybatis-plus-jsqlparser-common/src/main/java/com/baomidou/mybatisplus/jsqlparser/JsqlParserThreadPool.java
  21. 1 1
      mybatis-plus-jsqlparser-support/mybatis-plus-jsqlparser/build.gradle
  22. 15 0
      mybatis-plus-jsqlparser-support/mybatis-plus-jsqlparser/src/main/java/com/baomidou/mybatisplus/extension/parser/JsqlParserGlobal.java
  23. 25 1
      mybatis-plus-jsqlparser-support/mybatis-plus-jsqlparser/src/main/java/com/baomidou/mybatisplus/extension/parser/cache/FstFactory.java
  24. 1 1
      mybatis-plus-jsqlparser-support/mybatis-plus-jsqlparser/src/test/java/com/baomidou/mybatisplus/test/extension/plugins/inner/DynamicTableNameJsqlParserInnerInterceptorTest.java
  25. 38 0
      mybatis-plus-spring/src/main/java/com/baomidou/mybatisplus/extension/spi/SpringCompatibleSet.java
  26. 53 0
      mybatis-plus-spring/src/main/java/com/baomidou/mybatisplus/extension/spring/MybatisPlusApplicationContextAware.java
  27. 1 0
      mybatis-plus-spring/src/main/resources/META-INF/services/com.baomidou.mybatisplus.core.spi.CompatibleSet
  28. 11 0
      spring-boot-starter/mybatis-plus-spring-boot-autoconfigure/src/main/java/com/baomidou/mybatisplus/autoconfigure/MybatisPlusAutoConfiguration.java

+ 24 - 0
CHANGELOG.md

@@ -1,4 +1,28 @@
 # CHANGELOG
+## [v3.5.12] 2025.04.27
+- fix: 修复批量操作异步执行首次可能的出现`NoSuchElementException`错误
+- fix: 修复默认`SQL`解析线程池在`JVM`退出关闭导致的任务拒绝
+- fix: 修复`entity.java.btl`生成`toString`方法样式错误
+- fix: 修复`entity.java.ftl`模板类注释与导包缺少换行
+- opt: 重构`SqlRunner`执行`SQL`语句 (动态传参,不再根据参数值生成执行`SQL`)
+- opt: 增强`SqlRunner`执行(支持单参数使用`Map`({key}),`List`({index}),`JavaBean`({property})获取值)
+- opt: 改进`MybatisUtils`对自`SqlSessionFactory`的提取(支持自定义`SqlSessionTemplate`子类)
+- opt: 自动识别数据库支持`TDengine`数据库`websocket`连接
+- opt: 支持`Db`工具类对多数据源的支持
+- opt: 优化`MapperProxy`属性访问
+- opt: `CompatibleSet`接口增加`getBean`与`getProxyTargetObject`方法
+- opt: `CompatibleSet`与`CompatibleHelper`调整至`com.baomidou.mybatisplus.core.spi`包之中
+- opt: 支持手动指定`CompatibleSet`实现
+- opt: 代码生成器处理驱动返回索引信息`null`
+- opt: 代码生成器处理`PRIMARY_KEY_`为开头的主键索引情况
+- opt: 去除`entity.kt.btl`模板`@Override`注解
+- opt: 解决`serviceImpl.java.ej`生成格式不统一
+- opt: 去除`mapper.java.ftl`多余的换行生成
+- opt: 去除`entity.kt.vm`,`entity.kt.ej`,`entity.kt.btl`导包结束分隔符
+- opt: 去除`controller.java.ej`,`controller.java.vm`多余的换行
+- opt: 去除`entity.kt.btl`生成属性多余的空格
+- opt: 统一`entity.java.btl`,`entity.java.ej`,`entity.java.ftl`,`entity.java.vm` 生成的`toString`方法样式
+
 ## [v3.5.11] 2025.03.23
 - fix: 修复代码生成器链式模型非`lombok`下生成了`@Accessors`注解
 - fix: 修复主键使用`UUID`执行批量删除错

+ 2 - 16
changelog-temp.md

@@ -1,16 +1,2 @@
-- fix: 修复批量操作异步执行首次出现`NoSuchElementException`错误
-- fix: 修复`entity.java.btl`生成`toString`方法样式错误
-- fix: 修复`entity.java.ftl`模板类注释与导包缺少换行
-- opt: 支持手动指定`CompatibleSet`实现
-- opt: 去除`entity.kt.btl`模板`@Override`注解
-- opt: 解决`serviceImpl.java.ej`生成格式不统一
-- opt: 去除`mapper.java.ftl`多余的换行生成
-- opt: 去除`entity.kt.vm`,`entity.kt.ej`,`entity.kt.btl`导包结束分隔符
-- opt: 去除`controller.java.ej`,`controller.java.vm`多余的换行
-- opt: 去除`entity.kt.btl`生成属性多余的空格
-- opt: 代码生成器处理`PRIMARY_KEY_`为开头的主键索引情况
-- opt: 统一`entity.java.btl`,`entity.java.ej`,`entity.java.ftl`,`entity.java.vm` 生成的`toString`方法样式
-- opt: 重构`SqlRunner`执行`SQL`语句 (动态传参,不再根据参数值生成执行`SQL`)
-- opt: 增强`SqlRunner`执行(支持单参数使用`Map`({key}),`List`({index}),`JavaBean`({property})获取值)
-- opt: 改进`MybatisUtils`对自`SqlSessionFactory`的提取(支持自定义sqlSessionTemplate子类)
--
+- fix: 修复在`Spring`中使用`@PostConstruct`调用`Db`方法查询出现警告日志
+- feat: 升级`Jsqlparser`5.2

+ 1 - 1
gradle.properties

@@ -1,4 +1,4 @@
-APP_VERSION=3.5.12-SNAPSHOT
+APP_VERSION=3.5.13-SNAPSHOT
 APP_GROUP=com.baomidou
 signing.keyId=1FD337F9
 signing.password=243194995

+ 18 - 18
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/mapper/BaseMapper.java

@@ -22,9 +22,9 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.core.enums.SqlMethod;
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.metadata.MapperProxyMetadata;
 import com.baomidou.mybatisplus.core.metadata.TableInfo;
 import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
-import com.baomidou.mybatisplus.core.override.MybatisMapperProxy;
 import com.baomidou.mybatisplus.core.toolkit.*;
 import com.baomidou.mybatisplus.core.toolkit.reflect.GenericTypeUtils;
 import org.apache.ibatis.annotations.Param;
@@ -133,9 +133,9 @@ public interface BaseMapper<T> extends Mapper<T> {
                 return this.deleteById(instance);
             }
         }
-        MybatisMapperProxy<?> mybatisMapperProxy = MybatisUtils.getMybatisMapperProxy(this);
-        SqlSession sqlSession = mybatisMapperProxy.getSqlSession();
-        return sqlSession.delete(mybatisMapperProxy.getMapperInterface().getName() + Constants.DOT + SqlMethod.DELETE_BY_ID.getMethod(), obj);
+        MapperProxyMetadata mapperProxyMetadata = MybatisUtils.getMapperProxy(this);
+        SqlSession sqlSession = mapperProxyMetadata.getSqlSession();
+        return sqlSession.delete(mapperProxyMetadata.getMapperInterface().getName() + Constants.DOT + SqlMethod.DELETE_BY_ID.getMethod(), obj);
     }
 
     /**
@@ -206,10 +206,10 @@ public interface BaseMapper<T> extends Mapper<T> {
         if (CollectionUtils.isEmpty(collections)) {
             return 0;
         }
-        MybatisMapperProxy<?> mybatisMapperProxy = MybatisUtils.getMybatisMapperProxy(this);
+        MapperProxyMetadata mapperProxyMetadata = MybatisUtils.getMapperProxy(this);
         Class<?> entityClass = GenericTypeUtils.resolveTypeArguments(getClass(), BaseMapper.class)[0];
-        SqlSession sqlSession = mybatisMapperProxy.getSqlSession();
-        Class<?> mapperInterface = mybatisMapperProxy.getMapperInterface();
+        SqlSession sqlSession = mapperProxyMetadata.getSqlSession();
+        Class<?> mapperInterface = mapperProxyMetadata.getMapperInterface();
         TableInfo tableInfo = TableInfoHelper.getTableInfo(entityClass);
         Map<String, Object> params = new HashMap<>();
         if (useFill && tableInfo.isWithLogicDelete() && tableInfo.isWithUpdateFill()) {
@@ -505,9 +505,9 @@ public interface BaseMapper<T> extends Mapper<T> {
      * @since 3.5.7
      */
     default List<BatchResult> insert(Collection<T> entityList, int batchSize) {
-        MybatisMapperProxy<?> mybatisMapperProxy = MybatisUtils.getMybatisMapperProxy(this);
-        MybatisBatch.Method<T> method = new MybatisBatch.Method<>(mybatisMapperProxy.getMapperInterface());
-        SqlSessionFactory sqlSessionFactory = MybatisUtils.getSqlSessionFactory(mybatisMapperProxy);
+        MapperProxyMetadata mapperProxyMetadata = MybatisUtils.getMapperProxy(this);
+        MybatisBatch.Method<T> method = new MybatisBatch.Method<>(mapperProxyMetadata.getMapperInterface());
+        SqlSessionFactory sqlSessionFactory = MybatisUtils.getSqlSessionFactory(mapperProxyMetadata.getSqlSession());
         return MybatisBatchUtils.execute(sqlSessionFactory, entityList, method.insert(), batchSize);
     }
 
@@ -529,9 +529,9 @@ public interface BaseMapper<T> extends Mapper<T> {
      * @since 3.5.7
      */
     default List<BatchResult> updateById(Collection<T> entityList, int batchSize) {
-        MybatisMapperProxy<?> mybatisMapperProxy = MybatisUtils.getMybatisMapperProxy(this);
-        MybatisBatch.Method<T> method = new MybatisBatch.Method<>(mybatisMapperProxy.getMapperInterface());
-        SqlSessionFactory sqlSessionFactory = MybatisUtils.getSqlSessionFactory(mybatisMapperProxy);
+        MapperProxyMetadata mapperProxyMetadata = MybatisUtils.getMapperProxy(this);
+        MybatisBatch.Method<T> method = new MybatisBatch.Method<>(mapperProxyMetadata.getMapperInterface());
+        SqlSessionFactory sqlSessionFactory = MybatisUtils.getSqlSessionFactory(mapperProxyMetadata.getSqlSession());
         return MybatisBatchUtils.execute(sqlSessionFactory, entityList, method.updateById(), batchSize);
     }
 
@@ -553,11 +553,11 @@ public interface BaseMapper<T> extends Mapper<T> {
      * @since 3.5.7
      */
     default List<BatchResult> insertOrUpdate(Collection<T> entityList, int batchSize) {
-        MybatisMapperProxy<?> mybatisMapperProxy = MybatisUtils.getMybatisMapperProxy(this);
+        MapperProxyMetadata mapperProxyMetadata = MybatisUtils.getMapperProxy(this);
         Class<?> entityClass = GenericTypeUtils.resolveTypeArguments(getClass(), BaseMapper.class)[0];
         TableInfo tableInfo = TableInfoHelper.getTableInfo(entityClass);
         String keyProperty = tableInfo.getKeyProperty();
-        String statement = mybatisMapperProxy.getMapperInterface().getName() + StringPool.DOT + SqlMethod.SELECT_BY_ID.getMethod();
+        String statement = mapperProxyMetadata.getMapperInterface().getName() + StringPool.DOT + SqlMethod.SELECT_BY_ID.getMethod();
         return insertOrUpdate(entityList, (sqlSession, entity) -> {
             Object idVal = tableInfo.getPropertyValue(entity, keyProperty);
             return StringUtils.checkValNull(idVal) || CollectionUtils.isEmpty(sqlSession.selectList(statement, entity));
@@ -582,9 +582,9 @@ public interface BaseMapper<T> extends Mapper<T> {
      * @since 3.5.7
      */
     default List<BatchResult> insertOrUpdate(Collection<T> entityList, BiPredicate<BatchSqlSession, T> insertPredicate, int batchSize) {
-        MybatisMapperProxy<?> mybatisMapperProxy = MybatisUtils.getMybatisMapperProxy(this);
-        MybatisBatch.Method<T> method = new MybatisBatch.Method<>(mybatisMapperProxy.getMapperInterface());
-        SqlSessionFactory sqlSessionFactory = MybatisUtils.getSqlSessionFactory(mybatisMapperProxy);
+        MapperProxyMetadata mapperProxyMetadata = MybatisUtils.getMapperProxy(this);
+        MybatisBatch.Method<T> method = new MybatisBatch.Method<>(mapperProxyMetadata.getMapperInterface());
+        SqlSessionFactory sqlSessionFactory = MybatisUtils.getSqlSessionFactory(mapperProxyMetadata.getSqlSession());
         return MybatisBatchUtils.saveOrUpdate(sqlSessionFactory, entityList, method.insert(), insertPredicate, method.updateById(), batchSize);
     }
 

+ 62 - 0
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/metadata/MapperProxyMetadata.java

@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2011-2025, baomidou (jobob@qq.com).
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.baomidou.mybatisplus.core.metadata;
+
+import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
+import org.apache.ibatis.reflection.MetaObject;
+import org.apache.ibatis.session.SqlSession;
+
+/**
+ * Mapper代理属性
+ *
+ * @author nieqiurong
+ * @see com.baomidou.mybatisplus.core.override.MybatisMapperProxy
+ * @see org.apache.ibatis.binding.MapperProxy
+ * @since 3.5.12
+ */
+@SuppressWarnings("LombokGetterMayBeUsed")
+public class MapperProxyMetadata {
+
+    private final SqlSession sqlSession;
+
+    private final Class<?> mapperInterface;
+
+    public MapperProxyMetadata(MetaObject metaObject) {
+        if (!metaObject.hasGetter("mapperInterface") || !metaObject.hasGetter("sqlSession")) {
+            throw new MybatisPlusException("Unable to retrieve the mapperInterface and sqlSession properties from " + metaObject.getOriginalObject());
+        }
+        this.mapperInterface = (Class<?>) metaObject.getValue("mapperInterface");
+        this.sqlSession = (SqlSession) metaObject.getValue("sqlSession");
+    }
+
+    public Class<?> getMapperInterface() {
+        return mapperInterface;
+    }
+
+    public SqlSession getSqlSession() {
+        return sqlSession;
+    }
+
+    @Override
+    public String toString() {
+        return "MapperProxy{" +
+            "mapperInterface=" + mapperInterface +
+            ", sqlSession=" + sqlSession +
+            '}';
+    }
+
+
+}

+ 3 - 2
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/override/MybatisMapperProxy.java

@@ -15,6 +15,7 @@
  */
 package com.baomidou.mybatisplus.core.override;
 
+import com.baomidou.mybatisplus.core.metadata.MapperProxyMetadata;
 import com.baomidou.mybatisplus.core.plugins.IgnoreStrategy;
 import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
 import com.baomidou.mybatisplus.core.toolkit.MybatisUtils;
@@ -171,8 +172,8 @@ public class MybatisMapperProxy<T> implements InvocationHandler, Serializable {
                 return methodHandle.bindTo(proxy).invokeWithArguments(args);
             } else {
                 try {
-                    MybatisMapperProxy<?> mybatisMapperProxy = MybatisUtils.getMybatisMapperProxy(proxy);
-                    Class<?> mapperInterface = mybatisMapperProxy.getMapperInterface();
+                    MapperProxyMetadata mapperProxyMetadata = MybatisUtils.getMapperProxy(proxy);
+                    Class<?> mapperInterface = mapperProxyMetadata.getMapperInterface();
                     IgnoreStrategy ignoreStrategy = InterceptorIgnoreHelper.findIgnoreStrategy(mapperInterface, method);
                     if (ignoreStrategy == null) {
                         ignoreStrategy = IgnoreStrategy.builder().build();

+ 79 - 0
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/spi/CompatibleHelper.java

@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2011-2025, baomidou (jobob@qq.com).
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.baomidou.mybatisplus.core.spi;
+
+import com.baomidou.mybatisplus.core.toolkit.Assert;
+import org.apache.ibatis.logging.Log;
+import org.apache.ibatis.logging.LogFactory;
+
+import java.util.ServiceLoader;
+
+/**
+ * 兼容处理辅助类
+ * <p>默认加载使用SPI实现,需要手动指定请使用{@link #setCompatibleSet(CompatibleSet)}</p>
+ */
+public class CompatibleHelper {
+
+    private static final Log LOG = LogFactory.getLog(CompatibleHelper.class);
+
+    private static CompatibleSet COMPATIBLE_SET = null;
+
+    static {
+        ServiceLoader<CompatibleSet> loader = ServiceLoader.load(CompatibleSet.class, CompatibleSet.class.getClassLoader());
+        int size = 0;
+        for (CompatibleSet compatibleSet : loader) {
+            size++;
+            LOG.debug("Load compatibleSet: " + compatibleSet);
+            COMPATIBLE_SET = compatibleSet;
+        }
+        if (size > 1) {
+            LOG.warn("There are currently multiple implementations, and the last one is used " + COMPATIBLE_SET);
+        }
+    }
+
+    /**
+     * 判断是否存在 {@link com.baomidou.mybatisplus.core.spi.CompatibleSet} 实例
+     *
+     * @return 是否存在 (存在返回true,为空返回false)
+     * @since 3.5.12
+     */
+    public static boolean hasCompatibleSet() {
+        return COMPATIBLE_SET != null;
+    }
+
+    /**
+     * 手动指定 {@link com.baomidou.mybatisplus.core.spi.CompatibleSet} 实例
+     *
+     * @param compatibleSet {@link com.baomidou.mybatisplus.core.spi.CompatibleSet} 实例
+     * @since 3.5.12
+     */
+    public static void setCompatibleSet(CompatibleSet compatibleSet) {
+        COMPATIBLE_SET = compatibleSet;
+    }
+
+    /**
+     * 获取{@link com.baomidou.mybatisplus.core.spi.CompatibleSet}实例
+     * <p>当为空时会抛出异常,需要检查是否为空请使用{@link #hasCompatibleSet()}</p>
+     *
+     * @return {@link com.baomidou.mybatisplus.core.spi.CompatibleSet}
+     * @see #setCompatibleSet(CompatibleSet)
+     */
+    public static CompatibleSet getCompatibleSet() {
+        Assert.isTrue(hasCompatibleSet(), "Please add specific implementation dependencies or use the setCompatibleSet method to specify");
+        return COMPATIBLE_SET;
+    }
+
+}

+ 75 - 0
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/spi/CompatibleSet.java

@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2011-2025, baomidou (jobob@qq.com).
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.baomidou.mybatisplus.core.spi;
+
+import org.apache.ibatis.logging.Log;
+import org.apache.ibatis.session.SqlSession;
+import org.apache.ibatis.session.SqlSessionFactory;
+
+import java.io.InputStream;
+import java.util.function.Consumer;
+
+/**
+ * Web 开发平台待兼容方法集接口类
+ */
+public interface CompatibleSet {
+
+    SqlSession getSqlSession(SqlSessionFactory sessionFactory);
+
+    void closeSqlSession(SqlSession session, SqlSessionFactory sessionFactory);
+
+    boolean executeBatch(SqlSessionFactory sqlSessionFactory, Log log, Consumer<SqlSession> consumer);
+
+    /**
+     * @deprecated 3.5.12 无需实现
+     */
+    @Deprecated
+    default InputStream getInputStream(String path) throws Exception {
+        return null;
+    }
+
+    /**
+     * 获取容器bean实例
+     *
+     * @param clz 类型
+     * @return bean实例 (当无实例时返回null)
+     * @since 3.5.12
+     */
+    default <T> T getBean(Class<T> clz) {
+        return null;
+    }
+
+    /**
+     * 获取真实被代理的对象 (如果没有被代理,请返回原始对象)
+     *
+     * @param mapper Mapper对象
+     * @return 真实对象
+     * @since 3.5.12
+     */
+    default Object getProxyTargetObject(Object mapper) {
+        return null;
+    }
+
+    /**
+     * 传递上下文对象
+     * @param context 容器上下文
+     * @since 3.5.13
+     */
+    default void setContext(Object context) {
+
+    }
+
+}

+ 64 - 10
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/MybatisUtils.java

@@ -1,9 +1,26 @@
+/*
+ * Copyright (c) 2011-2025, baomidou (jobob@qq.com).
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package com.baomidou.mybatisplus.core.toolkit;
 
 import com.baomidou.mybatisplus.core.config.GlobalConfig;
 import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
 import com.baomidou.mybatisplus.core.handlers.IJsonTypeHandler;
+import com.baomidou.mybatisplus.core.metadata.MapperProxyMetadata;
 import com.baomidou.mybatisplus.core.override.MybatisMapperProxy;
+import com.baomidou.mybatisplus.core.spi.CompatibleHelper;
 import lombok.experimental.UtilityClass;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.ibatis.reflection.MetaObject;
@@ -14,7 +31,6 @@ import org.apache.ibatis.session.SqlSessionFactory;
 import org.apache.ibatis.session.defaults.DefaultSqlSession;
 import org.apache.ibatis.type.TypeException;
 import org.apache.ibatis.type.TypeHandler;
-import org.springframework.aop.framework.AopProxyUtils;
 
 import java.lang.reflect.Field;
 import java.lang.reflect.Proxy;
@@ -74,12 +90,23 @@ public class MybatisUtils {
      */
     public static SqlSessionFactory getSqlSessionFactory(MybatisMapperProxy<?> mybatisMapperProxy) {
         SqlSession sqlSession = mybatisMapperProxy.getSqlSession();
+        return getSqlSessionFactory(sqlSession);
+    }
+
+    /**
+     * 获取sqlSession中的SqlSessionFactory
+     *
+     * @param sqlSession sqlSession会话
+     * @return SqlSessionFactory
+     * @since 3.5.12
+     */
+    public static SqlSessionFactory getSqlSessionFactory(SqlSession sqlSession) {
         MetaObject metaObject = SystemMetaObject.forObject(sqlSession);
         String property = "sqlSessionFactory";
         if (metaObject.hasGetter(property)) {
             return (SqlSessionFactory) metaObject.getValue(property);
         }
-        SqlSessionFactory sqlSessionFactory = GlobalConfigUtils.getGlobalConfig(mybatisMapperProxy.getSqlSession().getConfiguration()).getSqlSessionFactory();
+        SqlSessionFactory sqlSessionFactory = GlobalConfigUtils.getGlobalConfig(sqlSession.getConfiguration()).getSqlSessionFactory();
         Assert.isTrue(sqlSessionFactory != null, "Please implement access to the sqlSessionFactory property or bind sqlSessionFactory to global access.");
         return sqlSessionFactory;
     }
@@ -92,14 +119,30 @@ public class MybatisUtils {
      * @since 3.5.7
      */
     public static MybatisMapperProxy<?> getMybatisMapperProxy(Object mapper) {
+        Object result = extractMapperProxy(mapper);
+        if (result instanceof MybatisMapperProxy) {
+            return (MybatisMapperProxy<?>) result;
+        }
+        throw new MybatisPlusException("Unable to get MybatisMapperProxy : " + mapper);
+    }
+
+    /**
+     * 提取MapperProxy
+     *
+     * @param mapper Mapper对象
+     * @return 真实Mapper对象(去除动态代理增强)
+     * @since 3.5.12
+     */
+    public static Object extractMapperProxy(Object mapper) {
         if (mapper instanceof MybatisMapperProxy) {
             // fast return
-            return (MybatisMapperProxy<?>) mapper;
+            return mapper;
         }
         Object result = mapper;
-        if (AopUtils.isLoadSpringAop()) {
-            while (org.springframework.aop.support.AopUtils.isAopProxy(result)) {
-                result = AopProxyUtils.getSingletonTarget(result);
+        if (CompatibleHelper.hasCompatibleSet()) {
+            Object proxyTargetObject = CompatibleHelper.getCompatibleSet().getProxyTargetObject(result);
+            if (proxyTargetObject != null) {
+                result = proxyTargetObject;
             }
         }
         if (result != null) {
@@ -107,10 +150,21 @@ public class MybatisUtils {
                 result = Proxy.getInvocationHandler(result);
             }
         }
-        if (result instanceof MybatisMapperProxy) {
-            return (MybatisMapperProxy<?>) result;
-        }
-        throw new MybatisPlusException("Unable to get MybatisMapperProxy : " + mapper);
+        return result;
+    }
+
+
+    /**
+     * 获取MapperProxy元数据信息
+     *
+     * @param mapper Mapper对象
+     * @return 代理属性
+     * @since 3.5.12
+     */
+    public static MapperProxyMetadata getMapperProxy(Object mapper) {
+        Object mapperProxy = extractMapperProxy(mapper);
+        MetaObject metaObject = SystemMetaObject.forObject(mapperProxy);
+        return new MapperProxyMetadata(metaObject);
     }
 
 }

+ 4 - 0
mybatis-plus-core/src/test/java/com/baomidou/mybatisplus/core/toolkit/MybatisUtilsTest.java

@@ -32,6 +32,7 @@ public class MybatisUtilsTest {
         var mybatisMapperProxy = new MybatisMapperProxy<>(sqlSession, MyMapper.class, new HashMap<>());
         SqlSessionFactory sqlSessionFactory = MybatisUtils.getSqlSessionFactory(mybatisMapperProxy);
         Assertions.assertNotNull(sqlSessionFactory);
+        Assertions.assertNotNull(MybatisUtils.getSqlSessionFactory(sqlSession));
     }
 
     @Test
@@ -40,6 +41,7 @@ public class MybatisUtilsTest {
         var mybatisMapperProxy = new MybatisMapperProxy<>(sqlSession, MyMapper.class, new HashMap<>());
         SqlSessionFactory sqlSessionFactory = MybatisUtils.getSqlSessionFactory(mybatisMapperProxy);
         Assertions.assertNotNull(sqlSessionFactory);
+        Assertions.assertNotNull(MybatisUtils.getSqlSessionFactory(sqlSession));
     }
 
     @Test
@@ -47,6 +49,7 @@ public class MybatisUtilsTest {
         var sqlSession = new SqlSessionTemplate(getDefaultSqlSessionFactory());
         var mybatisMapperProxy = new MybatisMapperProxy<>(sqlSession, MyMapper.class, new HashMap<>());
         Assertions.assertNotNull(MybatisUtils.getSqlSessionFactory(mybatisMapperProxy));
+        Assertions.assertNotNull(MybatisUtils.getSqlSessionFactory(sqlSession));
     }
 
     static class MySqlSessionTemplate extends SqlSessionTemplate {
@@ -61,6 +64,7 @@ public class MybatisUtilsTest {
         var sqlSession = new MySqlSessionTemplate(getDefaultSqlSessionFactory());
         var mybatisMapperProxy = new MybatisMapperProxy<>(sqlSession, MyMapper.class, new HashMap<>());
         Assertions.assertNotNull(MybatisUtils.getSqlSessionFactory(mybatisMapperProxy));
+        Assertions.assertNotNull(MybatisUtils.getSqlSessionFactory(sqlSession));
     }
 
     private SqlSessionFactory getDefaultSqlSessionFactory() {

+ 1 - 1
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/activerecord/AbstractModel.java

@@ -21,7 +21,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.metadata.TableInfo;
 import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
 import com.baomidou.mybatisplus.core.toolkit.*;
-import com.baomidou.mybatisplus.extension.spi.CompatibleHelper;
+import com.baomidou.mybatisplus.core.spi.CompatibleHelper;
 import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
 import org.apache.ibatis.logging.LogFactory;
 import org.apache.ibatis.session.SqlSession;

+ 5 - 5
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/repository/AbstractRepository.java

@@ -2,7 +2,7 @@ package com.baomidou.mybatisplus.extension.repository;
 
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.baomidou.mybatisplus.core.override.MybatisMapperProxy;
+import com.baomidou.mybatisplus.core.metadata.MapperProxyMetadata;
 import com.baomidou.mybatisplus.core.toolkit.MybatisUtils;
 import com.baomidou.mybatisplus.core.toolkit.reflect.GenericTypeUtils;
 import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
@@ -44,8 +44,8 @@ public abstract class AbstractRepository<M extends BaseMapper<T>, T>  implements
 
     protected SqlSessionFactory getSqlSessionFactory() {
         if (this.sqlSessionFactory == null) {
-            MybatisMapperProxy<?> mybatisMapperProxy = MybatisUtils.getMybatisMapperProxy(this.getBaseMapper());
-            this.sqlSessionFactory = MybatisUtils.getSqlSessionFactory(mybatisMapperProxy);
+            MapperProxyMetadata mapperProxyMetadata = MybatisUtils.getMapperProxy(this.getBaseMapper());
+            this.sqlSessionFactory = MybatisUtils.getSqlSessionFactory(mapperProxyMetadata.getSqlSession());
         }
         return this.sqlSessionFactory;
     }
@@ -56,8 +56,8 @@ public abstract class AbstractRepository<M extends BaseMapper<T>, T>  implements
      */
     public Class<M> getMapperClass() {
         if (this.mapperClass == null) {
-            MybatisMapperProxy<?> mybatisMapperProxy = MybatisUtils.getMybatisMapperProxy(this.getBaseMapper());
-            this.mapperClass = (Class<M>) mybatisMapperProxy.getMapperInterface();
+            MapperProxyMetadata mapperProxyMetadata = MybatisUtils.getMapperProxy(this.getBaseMapper());
+            this.mapperClass = (Class<M>) mapperProxyMetadata.getMapperInterface();
         }
         return this.mapperClass;
     }

+ 4 - 0
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/spi/CompatibleHelper.java

@@ -24,7 +24,11 @@ import java.util.ServiceLoader;
 /**
  * 兼容处理辅助类
  * <p>默认加载使用SPI实现,需要手动指定请使用{@link #setCompatibleSet(CompatibleSet)}</p>
+ *
+ * @see com.baomidou.mybatisplus.core.spi.CompatibleHelper
+ * @deprecated 3.5.12
  */
+@Deprecated
 public class CompatibleHelper {
 
     private static final Log LOG = LogFactory.getLog(CompatibleHelper.class);

+ 5 - 20
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/spi/CompatibleSet.java

@@ -15,28 +15,13 @@
  */
 package com.baomidou.mybatisplus.extension.spi;
 
-import org.apache.ibatis.logging.Log;
-import org.apache.ibatis.session.SqlSession;
-import org.apache.ibatis.session.SqlSessionFactory;
-
-import java.io.InputStream;
-import java.util.function.Consumer;
-
 /**
  * Web 开发平台待兼容方法集接口类
+ *
+ * @see com.baomidou.mybatisplus.core.spi.CompatibleSet
+ * @deprecated 3.5.12
  */
-public interface CompatibleSet {
-
-    SqlSession getSqlSession(SqlSessionFactory sessionFactory);
-
-    void closeSqlSession(SqlSession session, SqlSessionFactory sessionFactory);
-
-    boolean executeBatch(SqlSessionFactory sqlSessionFactory, Log log, Consumer<SqlSession> consumer);
-
-    /**
-     * @deprecated 3.5.12 无需实现
-     */
-    @Deprecated
-    InputStream getInputStream(String path) throws Exception;
+@Deprecated
+public interface CompatibleSet extends com.baomidou.mybatisplus.core.spi.CompatibleSet {
 
 }

+ 1 - 1
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/toolkit/JdbcUtils.java

@@ -131,7 +131,7 @@ public class JdbcUtils {
             return DbType.REDSHIFT;
         } else if (url.contains(":opengauss:")) {
             return DbType.OPENGAUSS;
-        } else if (url.contains(":taos:") || url.contains(":taos-rs:")) {
+        } else if (url.contains(":taos:") || url.contains(":taos-rs:") || url.contains(":taos-ws:")) {
             return DbType.TDENGINE;
         } else if (url.contains(":informix")) {
             return DbType.INFORMIX;

+ 9 - 1
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/toolkit/SqlHelper.java

@@ -21,7 +21,8 @@ import com.baomidou.mybatisplus.core.metadata.TableInfo;
 import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
 import com.baomidou.mybatisplus.core.toolkit.*;
 import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
-import com.baomidou.mybatisplus.extension.spi.CompatibleHelper;
+import com.baomidou.mybatisplus.core.spi.CompatibleHelper;
+import com.baomidou.mybatisplus.core.spi.CompatibleSet;
 import org.apache.ibatis.executor.BatchResult;
 import org.apache.ibatis.logging.Log;
 import org.apache.ibatis.session.ExecutorType;
@@ -296,6 +297,13 @@ public final class SqlHelper {
         Assert.notNull(entityClass, "entityClass can't be null!");
         TableInfo tableInfo = Optional.ofNullable(TableInfoHelper.getTableInfo(entityClass)).orElseThrow(() -> ExceptionUtils.mpe("Can not find TableInfo from Class: \"%s\".", entityClass.getName()));
         Class<?> mapperClass = ClassUtils.toClassConfident(tableInfo.getCurrentNamespace());
+        if (CompatibleHelper.hasCompatibleSet()) {
+            CompatibleSet compatibleSet = CompatibleHelper.getCompatibleSet();
+            Object bean = compatibleSet.getBean(mapperClass);
+            if (bean != null) {
+                return (M) bean;
+            }
+        }
         return (M) tableInfo.getConfiguration().getMapper(mapperClass, sqlSession);
     }
 

+ 10 - 7
mybatis-plus-generator/src/main/java/com/baomidou/mybatisplus/generator/jdbc/DatabaseMetaDataWrapper.java

@@ -70,7 +70,7 @@ public class DatabaseMetaDataWrapper {
             try {
                 con.close();
             } catch (SQLException sqlException) {
-                sqlException.printStackTrace();
+                logger.error("关闭数据库连接出现错误:", sqlException);
             }
         });
     }
@@ -82,15 +82,18 @@ public class DatabaseMetaDataWrapper {
     public List<DatabaseMetaDataWrapper.Index> getIndex(String tableName) {
         List<DatabaseMetaDataWrapper.Index> indexList = new ArrayList<>();
         try (ResultSet resultSet = databaseMetaData.getIndexInfo(catalog, schema, tableName, false, false)) {
-            while (resultSet.next()) {
-                Index index = new Index(resultSet);
-                // skip function index
-                if (StringUtils.isNotBlank(index.getColumnName())) {
-                    indexList.add(new Index(resultSet));
+            // clickhouse v2驱动没实现返回了个null
+            if (resultSet != null) {
+                while (resultSet.next()) {
+                    Index index = new Index(resultSet);
+                    // skip function index
+                    if (StringUtils.isNotBlank(index.getColumnName())) {
+                        indexList.add(index);
+                    }
                 }
             }
         } catch (SQLException e) {
-            throw new RuntimeException("读取索引信息:" + tableName + "错误:", e);
+            logger.error("读取{}索引信息出现错误:", tableName, e);
         }
         return indexList;
     }

+ 15 - 0
mybatis-plus-jsqlparser-support/mybatis-plus-jsqlparser-4.9/src/main/java/com/baomidou/mybatisplus/extension/parser/JsqlParserGlobal.java

@@ -79,7 +79,9 @@ public class JsqlParserGlobal {
      * @param executorService 线程池 (自行控制线程池关闭)
      * @param addShutdownHook 是否注册退出关闭钩子
      * @since 3.5.11
+     * @deprecated 3.5.12 推荐使用 {@link #setExecutorService(ExecutorService, Thread)}
      */
+    @Deprecated
     public static void setExecutorService(ExecutorService executorService, boolean addShutdownHook) {
         JsqlParserGlobal.executorService = executorService;
         if (addShutdownHook) {
@@ -87,6 +89,19 @@ public class JsqlParserGlobal {
         }
     }
 
+    /**
+     * 设置解析线程池
+     * @param executorService 线程池 (自行控制线程池关闭)
+     * @param shutdownHook 关闭钩子
+     * @since 3.5.12
+     */
+    public static void setExecutorService(ExecutorService executorService, Thread shutdownHook) {
+        JsqlParserGlobal.executorService = executorService;
+        if (shutdownHook != null) {
+            Runtime.getRuntime().addShutdownHook(shutdownHook);
+        }
+    }
+
     /**
      * 获取解析线程池(如果未自定义则返回默认的解析线程池)
      *

+ 14 - 0
mybatis-plus-jsqlparser-support/mybatis-plus-jsqlparser-5.0/src/main/java/com/baomidou/mybatisplus/extension/parser/JsqlParserGlobal.java

@@ -79,7 +79,9 @@ public class JsqlParserGlobal {
      * @param executorService 线程池 (自行控制线程池关闭)
      * @param addShutdownHook 是否注册退出关闭钩子
      * @since 3.5.11
+     * @deprecated 3.5.12 推荐使用 {@link #setExecutorService(ExecutorService, Thread)}
      */
+    @Deprecated
     public static void setExecutorService(ExecutorService executorService, boolean addShutdownHook) {
         JsqlParserGlobal.executorService = executorService;
         if (addShutdownHook) {
@@ -87,6 +89,18 @@ public class JsqlParserGlobal {
         }
     }
 
+    /**
+     * 设置解析线程池
+     * @param executorService 线程池 (自行控制线程池关闭)
+     * @param shutdownHook 关闭钩子
+     * @since 3.5.12
+     */
+    public static void setExecutorService(ExecutorService executorService, Thread shutdownHook) {
+        JsqlParserGlobal.executorService = executorService;
+        if (shutdownHook != null) {
+            Runtime.getRuntime().addShutdownHook(shutdownHook);
+        }
+    }
     /**
      * 获取解析线程池(如果未自定义则返回默认的解析线程池)
      *

+ 2 - 4
mybatis-plus-jsqlparser-support/mybatis-plus-jsqlparser-common/src/main/java/com/baomidou/mybatisplus/jsqlparser/JsqlParserThreadPool.java

@@ -47,7 +47,9 @@ public class JsqlParserThreadPool {
      * 注册Jvm退出钩子
      *
      * @param executorService 线程池
+     * @deprecated 3.5.12
      */
+    @Deprecated
     public static void addShutdownHook(ExecutorService executorService) {
         Runtime.getRuntime().addShutdownHook(new Thread(() -> {
             if (!executorService.isShutdown()) {
@@ -67,10 +69,6 @@ public class JsqlParserThreadPool {
             return thread;
         });
 
-        static {
-            addShutdownHook(executorService);
-        }
-
         /**
          * 默认解析线程池(固定大小,默认大小{@link #DEFAULT_THREAD_SIZE})
          *

+ 1 - 1
mybatis-plus-jsqlparser-support/mybatis-plus-jsqlparser/build.gradle

@@ -3,7 +3,7 @@ compileJava {
 }
 
 dependencies {
-    api "com.github.jsqlparser:jsqlparser:5.1"
+    api "com.github.jsqlparser:jsqlparser:5.2"
     api project(":mybatis-plus-jsqlparser-support:mybatis-plus-jsqlparser-common")
     implementation "${lib."slf4j-api"}"
     implementation "de.ruedigermoeller:fst:3.0.3"

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

@@ -79,7 +79,9 @@ public class JsqlParserGlobal {
      * @param executorService 线程池 (自行控制线程池关闭)
      * @param addShutdownHook 是否注册退出关闭钩子
      * @since 3.5.11
+     * @deprecated 3.5.12 推荐使用 {@link #setExecutorService(ExecutorService, Thread)}
      */
+    @Deprecated
     public static void setExecutorService(ExecutorService executorService, boolean addShutdownHook) {
         JsqlParserGlobal.executorService = executorService;
         if (addShutdownHook) {
@@ -87,6 +89,19 @@ public class JsqlParserGlobal {
         }
     }
 
+    /**
+     * 设置解析线程池
+     * @param executorService 线程池 (自行控制线程池关闭)
+     * @param shutdownHook 关闭钩子
+     * @since 3.5.12
+     */
+    public static void setExecutorService(ExecutorService executorService, Thread shutdownHook) {
+        JsqlParserGlobal.executorService = executorService;
+        if (shutdownHook != null) {
+            Runtime.getRuntime().addShutdownHook(shutdownHook);
+        }
+    }
+
     /**
      * 获取解析线程池(如果未自定义则返回默认的解析线程池)
      *

+ 25 - 1
mybatis-plus-jsqlparser-support/mybatis-plus-jsqlparser/src/main/java/com/baomidou/mybatisplus/extension/parser/cache/FstFactory.java

@@ -78,6 +78,7 @@ public class FstFactory {
         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.PreferringClause.class);
         conf.registerClass(net.sf.jsqlparser.expression.RangeExpression.class);
@@ -134,6 +135,7 @@ public class FstFactory {
         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.IsUnknownExpression.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);
@@ -180,6 +182,8 @@ public class FstFactory {
         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.AlterExpression.ColumnSetDefault.class);
+        conf.registerClass(net.sf.jsqlparser.statement.alter.AlterExpression.ColumnSetVisibility.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);
@@ -218,6 +222,24 @@ public class FstFactory {
         conf.registerClass(net.sf.jsqlparser.statement.merge.MergeDelete.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.piped.AggregatePipeOperator.class);
+        conf.registerClass(net.sf.jsqlparser.statement.piped.AsPipeOperator.class);
+        conf.registerClass(net.sf.jsqlparser.statement.piped.CallPipeOperator.class);
+        conf.registerClass(net.sf.jsqlparser.statement.piped.DropPipeOperator.class);
+        conf.registerClass(net.sf.jsqlparser.statement.piped.ExtendPipeOperator.class);
+        conf.registerClass(net.sf.jsqlparser.statement.piped.FromQuery.class);
+        conf.registerClass(net.sf.jsqlparser.statement.piped.JoinPipeOperator.class);
+        conf.registerClass(net.sf.jsqlparser.statement.piped.LimitPipeOperator.class);
+        conf.registerClass(net.sf.jsqlparser.statement.piped.OrderByPipeOperator.class);
+        conf.registerClass(net.sf.jsqlparser.statement.piped.PivotPipeOperator.class);
+        conf.registerClass(net.sf.jsqlparser.statement.piped.RenamePipeOperator.class);
+        conf.registerClass(net.sf.jsqlparser.statement.piped.SelectPipeOperator.class);
+        conf.registerClass(net.sf.jsqlparser.statement.piped.SetOperationPipeOperator.class);
+        conf.registerClass(net.sf.jsqlparser.statement.piped.SetPipeOperator.class);
+        conf.registerClass(net.sf.jsqlparser.statement.piped.TableSamplePipeOperator.class);
+        conf.registerClass(net.sf.jsqlparser.statement.piped.UnPivotPipeOperator.class);
+        conf.registerClass(net.sf.jsqlparser.statement.piped.WherePipeOperator.class);
+        conf.registerClass(net.sf.jsqlparser.statement.piped.WindowPipeOperator.class);
         conf.registerClass(net.sf.jsqlparser.statement.refresh.RefreshMaterializedViewStatement.class);
         conf.registerClass(net.sf.jsqlparser.statement.select.AllColumns.class);
         conf.registerClass(net.sf.jsqlparser.statement.select.AllTableColumns.class);
@@ -226,6 +248,7 @@ public class FstFactory {
         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.ForClause.class);
+        conf.registerClass(net.sf.jsqlparser.statement.select.FunctionAllColumns.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);
@@ -254,6 +277,7 @@ public class FstFactory {
         conf.registerClass(net.sf.jsqlparser.statement.select.Values.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);
@@ -267,10 +291,10 @@ public class FstFactory {
         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.piped.PipeOperator.class);
         conf.registerClass(net.sf.jsqlparser.statement.select.Select.class);
         conf.registerClass(net.sf.jsqlparser.statement.select.SetOperation.class);
         conf.registerClass(net.sf.jsqlparser.util.cnfexpression.MultipleExpression.class);
-
     }
 
     public byte[] asByteArray(Object obj) {

+ 1 - 1
mybatis-plus-jsqlparser-support/mybatis-plus-jsqlparser/src/test/java/com/baomidou/mybatisplus/test/extension/plugins/inner/DynamicTableNameJsqlParserInnerInterceptorTest.java

@@ -515,7 +515,7 @@ class DynamicTableNameJsqlParserInnerInterceptorTest {
         var sql = "CREATE FULLTEXT INDEX index_name ON table1 (a, b)";
         assertEquals("CREATE FULLTEXT INDEX index_name ON table1_r (a, b)", interceptor.changeTable(sql));
         sql = "ALTER TABLE table1 ADD FULLTEXT INDEX `a`(`a`)";
-        assertEquals("ALTER TABLE table1_r ADD FULLTEXT INDEX `a`(`a`)", interceptor.changeTable(sql));
+        assertEquals("ALTER TABLE table1_r ADD FULLTEXT INDEX `a` (`a`)", interceptor.changeTable(sql));
     }
 
 

+ 38 - 0
mybatis-plus-spring/src/main/java/com/baomidou/mybatisplus/extension/spi/SpringCompatibleSet.java

@@ -15,10 +15,13 @@
  */
 package com.baomidou.mybatisplus.extension.spi;
 
+import com.baomidou.mybatisplus.core.toolkit.AopUtils;
 import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
+import com.baomidou.mybatisplus.extension.spring.MybatisPlusApplicationContextAware;
 import lombok.SneakyThrows;
 import org.apache.ibatis.exceptions.PersistenceException;
 import org.apache.ibatis.logging.Log;
+import org.apache.ibatis.logging.LogFactory;
 import org.apache.ibatis.reflection.ExceptionUtil;
 import org.apache.ibatis.session.ExecutorType;
 import org.apache.ibatis.session.SqlSession;
@@ -26,6 +29,9 @@ import org.apache.ibatis.session.SqlSessionFactory;
 import org.mybatis.spring.MyBatisExceptionTranslator;
 import org.mybatis.spring.SqlSessionHolder;
 import org.mybatis.spring.SqlSessionUtils;
+import org.springframework.aop.framework.AopProxyUtils;
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.context.ApplicationContext;
 import org.springframework.core.io.ClassPathResource;
 import org.springframework.transaction.support.TransactionSynchronizationManager;
 
@@ -37,6 +43,10 @@ import java.util.function.Consumer;
  */
 public class SpringCompatibleSet implements CompatibleSet {
 
+    private static final Log LOG = LogFactory.getLog(SpringCompatibleSet.class);
+
+    private static volatile ApplicationContext applicationContext;
+
     @Override
     public SqlSession getSqlSession(SqlSessionFactory sessionFactory) {
         return SqlSessionUtils.getSqlSession(sessionFactory);
@@ -88,4 +98,32 @@ public class SpringCompatibleSet implements CompatibleSet {
     public InputStream getInputStream(String path) throws Exception {
         return new ClassPathResource(path).getInputStream();
     }
+
+    @Override
+    public <T> T getBean(Class<T> clz) {
+        if (applicationContext == null && !MybatisPlusApplicationContextAware.hasApplicationContext()) {
+            LOG.warn("MybatisPlusApplicationContextAware is not initialized. Please ensure that MybatisPlusApplicationContextAware is properly registered as a Spring Bean in the application context.");
+            return null;
+        }
+        ApplicationContext context = applicationContext !=null  ? applicationContext : MybatisPlusApplicationContextAware.getApplicationContext();
+        ObjectProvider<T> provider = context.getBeanProvider(clz);
+        return provider.getIfAvailable();
+    }
+
+    @Override
+    public Object getProxyTargetObject(Object mapper) {
+        Object result = mapper;
+        if (AopUtils.isLoadSpringAop()) {
+            while (org.springframework.aop.support.AopUtils.isAopProxy(result)) {
+                result = AopProxyUtils.getSingletonTarget(result);
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public void setContext(Object context) {
+        applicationContext = (ApplicationContext) context;
+    }
+
 }

+ 53 - 0
mybatis-plus-spring/src/main/java/com/baomidou/mybatisplus/extension/spring/MybatisPlusApplicationContextAware.java

@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2011-2025, baomidou (jobob@qq.com).
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.baomidou.mybatisplus.extension.spring;
+
+import com.baomidou.mybatisplus.core.toolkit.Assert;
+import org.jetbrains.annotations.NotNull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+
+/**
+ * Spring容器访问
+ *
+ * @author nieqiurong
+ * @since 3.5.12
+ */
+public class MybatisPlusApplicationContextAware implements ApplicationContextAware {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(MybatisPlusApplicationContextAware.class);
+
+    private static ApplicationContext applicationContext;
+
+    @Override
+    public void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException {
+        LOGGER.info("Register ApplicationContext instances {}", applicationContext.getDisplayName());
+        MybatisPlusApplicationContextAware.applicationContext = applicationContext;
+    }
+
+    public static boolean hasApplicationContext() {
+        return applicationContext != null;
+    }
+
+    public static ApplicationContext getApplicationContext() {
+        Assert.isTrue(hasApplicationContext(), "applicationContext is null");
+        return applicationContext;
+    }
+
+}

+ 1 - 0
mybatis-plus-spring/src/main/resources/META-INF/services/com.baomidou.mybatisplus.core.spi.CompatibleSet

@@ -0,0 +1 @@
+com.baomidou.mybatisplus.extension.spi.SpringCompatibleSet

+ 11 - 0
spring-boot-starter/mybatis-plus-spring-boot-autoconfigure/src/main/java/com/baomidou/mybatisplus/autoconfigure/MybatisPlusAutoConfiguration.java

@@ -24,6 +24,8 @@ import com.baomidou.mybatisplus.core.handlers.PostInitTableInfoHandler;
 import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator;
 import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
 import com.baomidou.mybatisplus.core.injector.ISqlInjector;
+import com.baomidou.mybatisplus.core.spi.CompatibleHelper;
+import com.baomidou.mybatisplus.extension.spring.MybatisPlusApplicationContextAware;
 import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.mapping.DatabaseIdProvider;
@@ -147,6 +149,9 @@ public class MybatisPlusAutoConfiguration implements InitializingBean {
         if (!CollectionUtils.isEmpty(mybatisPlusPropertiesCustomizers)) {
             mybatisPlusPropertiesCustomizers.forEach(i -> i.customize(properties));
         }
+        if (CompatibleHelper.hasCompatibleSet()) {
+            CompatibleHelper.getCompatibleSet().setContext(applicationContext);
+        }
         checkConfigFileExists();
     }
 
@@ -375,4 +380,10 @@ public class MybatisPlusAutoConfiguration implements InitializingBean {
         }
     }
 
+    @Bean
+    @ConditionalOnMissingBean(MybatisPlusApplicationContextAware.class)
+    public MybatisPlusApplicationContextAware mybatisPlusSpringApplicationContextAware() {
+        return new MybatisPlusApplicationContextAware();
+    }
+
 }