Sfoglia il codice sorgente

支持 solon 启动插件模块结构扩展包

hubin 6 mesi fa
parent
commit
ea714cf111
58 ha cambiato i file con 1962 aggiunte e 536 eliminazioni
  1. 4 0
      .kotlin/errors/errors-1726886507129.log
  2. 5 0
      changelog-temp.md
  3. 1 1
      gradle.properties
  4. 0 1
      mybatis-plus-core/src/test/java/com/baomidou/mybatisplus/test/mapper/BMapper.java
  5. 0 3
      mybatis-plus-extension/build.gradle
  6. 4 12
      mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/activerecord/AbstractModel.java
  7. 3 7
      mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/ddl/DdlHelper.java
  8. 128 0
      mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/repository/AbstractRepository.java
  9. 9 131
      mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/repository/IRepository.java
  10. 0 310
      mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/service/impl/ServiceImpl.java
  11. 8 46
      mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/toolkit/SqlHelper.java
  12. 1 2
      mybatis-plus-generator/src/main/java/com/baomidou/mybatisplus/generator/config/po/TableInfo.java
  13. 17 0
      mybatis-plus-solon-plugin/build.gradle
  14. 33 0
      mybatis-plus-solon-plugin/src/main/java/com/baomidou/mybatisplus/core/override/SolonMybatisMapperProxy.java
  15. 39 0
      mybatis-plus-solon-plugin/src/main/java/com/baomidou/mybatisplus/extension/activerecord/Model.java
  16. 80 0
      mybatis-plus-solon-plugin/src/main/java/com/baomidou/mybatisplus/extension/compatible/SolonCompatibleSet.java
  17. 45 0
      mybatis-plus-solon-plugin/src/main/java/com/baomidou/mybatisplus/extension/ddl/SimpleDdl.java
  18. 103 0
      mybatis-plus-solon-plugin/src/main/java/com/baomidou/mybatisplus/extension/repository/CrudRepository.java
  19. 72 0
      mybatis-plus-solon-plugin/src/main/java/com/baomidou/mybatisplus/extension/service/IService.java
  20. 30 0
      mybatis-plus-solon-plugin/src/main/java/com/baomidou/mybatisplus/extension/service/impl/ServiceImpl.java
  21. 0 0
      mybatis-plus-solon-plugin/src/main/java/com/baomidou/mybatisplus/extension/service/impl/package-info.java
  22. 0 0
      mybatis-plus-solon-plugin/src/main/java/com/baomidou/mybatisplus/extension/service/package-info.java
  23. 244 0
      mybatis-plus-solon-plugin/src/main/java/com/baomidou/mybatisplus/extension/toolkit/SqlRunner.java
  24. 24 0
      mybatis-plus-solon-plugin/src/main/java/com/baomidou/mybatisplus/solon/integration/MybatisAdapterFactoryPlus.java
  25. 146 0
      mybatis-plus-solon-plugin/src/main/java/com/baomidou/mybatisplus/solon/integration/MybatisAdapterPlus.java
  26. 209 0
      mybatis-plus-solon-plugin/src/main/java/com/baomidou/mybatisplus/solon/integration/SolonSqlSession.java
  27. 39 0
      mybatis-plus-solon-plugin/src/main/java/com/baomidou/mybatisplus/solon/integration/XPluginImpl.java
  28. 68 0
      mybatis-plus-solon-plugin/src/main/java/com/baomidou/mybatisplus/solon/integration/aot/MybatisPlusRuntimeNativeRegistrar.java
  29. 2 0
      mybatis-plus-solon-plugin/src/main/resources/META-INF/solon/mybatis-plus-solon-plugin.properties
  30. 50 0
      mybatis-plus-solon-plugin/src/test/java/demo/Config.java
  31. 22 0
      mybatis-plus-solon-plugin/src/test/java/demo/DemoApp.java
  32. 21 0
      mybatis-plus-solon-plugin/src/test/java/demo/controller/IndexController.java
  33. 19 0
      mybatis-plus-solon-plugin/src/test/java/demo/dso/MetaObjectHandlerImpl.java
  34. 9 0
      mybatis-plus-solon-plugin/src/test/java/demo/dso/MybatisSqlSessionFactoryBuilderImpl.java
  35. 10 0
      mybatis-plus-solon-plugin/src/test/java/demo/dso/mapper/UserMapper.java
  36. 24 0
      mybatis-plus-solon-plugin/src/test/java/demo/dso/service/UserService.java
  37. 31 0
      mybatis-plus-solon-plugin/src/test/java/demo/model/User.java
  38. 27 0
      mybatis-plus-solon-plugin/src/test/java/features/IGenericTypeResolverImplTest.java
  39. 25 0
      mybatis-plus-solon-plugin/src/test/resources/app.yml
  40. 29 0
      mybatis-plus-spring/build.gradle
  41. 39 0
      mybatis-plus-spring/src/main/java/com/baomidou/mybatisplus/extension/activerecord/Model.java
  42. 91 0
      mybatis-plus-spring/src/main/java/com/baomidou/mybatisplus/extension/compatible/SpringCompatibleSet.java
  43. 0 0
      mybatis-plus-spring/src/main/java/com/baomidou/mybatisplus/extension/ddl/SimpleDdl.java
  44. 103 0
      mybatis-plus-spring/src/main/java/com/baomidou/mybatisplus/extension/repository/CrudRepository.java
  45. 75 0
      mybatis-plus-spring/src/main/java/com/baomidou/mybatisplus/extension/service/IService.java
  46. 30 0
      mybatis-plus-spring/src/main/java/com/baomidou/mybatisplus/extension/service/impl/ServiceImpl.java
  47. 22 0
      mybatis-plus-spring/src/main/java/com/baomidou/mybatisplus/extension/service/impl/package-info.java
  48. 5 2
      mybatis-plus-spring/src/main/java/com/baomidou/mybatisplus/extension/service/package-info.java
  49. 2 12
      mybatis-plus-spring/src/main/java/com/baomidou/mybatisplus/extension/spring/MybatisSqlSessionFactoryBean.java
  50. 0 0
      mybatis-plus-spring/src/main/java/com/baomidou/mybatisplus/extension/toolkit/SqlRunner.java
  51. 0 1
      mybatis-plus-spring/src/test/java/com/baomidou/mybatisplus/test/service/ServiceTest.java
  52. 1 0
      mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/logicdel/EntityMapper.java
  53. 0 1
      mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/phoenix/PhoenixTest.java
  54. 0 2
      mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/sqlrunner/SqlRunnerTest.java
  55. 4 5
      mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/toolkit/SqlHelperTest.java
  56. 2 0
      settings.gradle
  57. 2 0
      spring-boot-starter/mybatis-plus-spring-boot-autoconfigure/build.gradle
  58. 5 0
      spring-boot-starter/mybatis-plus-spring-boot-autoconfigure/src/main/java/com/baomidou/mybatisplus/autoconfigure/MybatisPlusAutoConfiguration.java

+ 4 - 0
.kotlin/errors/errors-1726886507129.log

@@ -0,0 +1,4 @@
+kotlin version: 2.0.20
+error message: The daemon has terminated unexpectedly on startup attempt #1 with error code: 0. The daemon process output:
+    1. Kotlin compile daemon is ready
+

+ 5 - 0
changelog-temp.md

@@ -0,0 +1,5 @@
+
+- opt: 优化代码生成器支持可视化配置生产能力
+- opt: 解构扩展包不再强制依赖 spring 开发框架
+- feat: 重构 service 模块抽象为 CrudRepository 不再建议使用 IService 避免业务层数据混乱
+- feat: 新增 solon 启动插件支持

+ 1 - 1
gradle.properties

@@ -1,4 +1,4 @@
-APP_VERSION=3.5.8
+APP_VERSION=3.5.9
 APP_GROUP=com.baomidou
 signing.keyId=1FD337F9
 signing.password=243194995

+ 0 - 1
mybatis-plus-core/src/test/java/com/baomidou/mybatisplus/test/mapper/BMapper.java

@@ -1,7 +1,6 @@
 package com.baomidou.mybatisplus.test.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.baomidou.mybatisplus.test.entity.AEntity;
 import com.baomidou.mybatisplus.test.entity.BEntity;
 
 public interface BMapper extends BaseMapper<BEntity> {

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

@@ -6,12 +6,9 @@ compileKotlin{
 
 dependencies {
     api project(":mybatis-plus-core")
-    implementation "${lib."mybatis-spring"}"
 
     implementation "${lib."kotlin-stdlib-jdk8"}"
     implementation "${lib."kotlin-reflect"}"
-    implementation "${lib."spring-context-support"}"
-    implementation "${lib."spring-jdbc"}"
     implementation "${lib."slf4j-api"}"
     implementation "${lib."p6spy"}"
     implementation "${lib."jackson"}"

+ 4 - 12
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/activerecord/Model.java → mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/activerecord/AbstractModel.java

@@ -21,11 +21,10 @@ 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.compatible.CompatibleHelper;
 import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
-import com.baomidou.mybatisplus.extension.toolkit.SqlRunner;
 import org.apache.ibatis.logging.LogFactory;
 import org.apache.ibatis.session.SqlSession;
-import org.mybatis.spring.SqlSessionUtils;
 
 import java.io.Serializable;
 import java.util.List;
@@ -43,11 +42,11 @@ import java.util.Objects;
  * @author hubin
  * @since 2016-11-06
  */
-public abstract class Model<T extends Model<?>> implements Serializable {
+public abstract class AbstractModel<T extends AbstractModel<?>> implements Serializable {
 
     private static final long serialVersionUID = 1L;
 
-    private final transient Class<?> entityClass = this.getClass();
+    protected final transient Class<?> entityClass = this.getClass();
 
     /**
      * 插入(字段选择插入)
@@ -237,13 +236,6 @@ public abstract class Model<T extends Model<?>> implements Serializable {
         }
     }
 
-    /**
-     * 执行 SQL
-     */
-    public SqlRunner sql() {
-        return new SqlRunner(this.entityClass);
-    }
-
     /**
      * 获取Session 默认自动提交
      */
@@ -284,6 +276,6 @@ public abstract class Model<T extends Model<?>> implements Serializable {
      * @param sqlSession session
      */
     protected void closeSqlSession(SqlSession sqlSession) {
-        SqlSessionUtils.closeSqlSession(sqlSession, GlobalConfigUtils.currentSessionFactory(this.entityClass));
+        CompatibleHelper.getCompatibleSet().closeSqlSession(sqlSession, GlobalConfigUtils.currentSessionFactory(this.entityClass));
     }
 }

+ 3 - 7
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/ddl/DdlHelper.java

@@ -17,17 +17,13 @@ package com.baomidou.mybatisplus.extension.ddl;
 
 import com.baomidou.mybatisplus.annotation.DbType;
 import com.baomidou.mybatisplus.core.toolkit.StringPool;
-import com.baomidou.mybatisplus.extension.ddl.history.IDdlGenerator;
-import com.baomidou.mybatisplus.extension.ddl.history.MysqlDdlGenerator;
-import com.baomidou.mybatisplus.extension.ddl.history.OracleDdlGenerator;
-import com.baomidou.mybatisplus.extension.ddl.history.PostgreDdlGenerator;
-import com.baomidou.mybatisplus.extension.ddl.history.SQLiteDdlGenerator;
+import com.baomidou.mybatisplus.extension.compatible.CompatibleHelper;
+import com.baomidou.mybatisplus.extension.ddl.history.*;
 import com.baomidou.mybatisplus.extension.toolkit.JdbcUtils;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.ibatis.io.Resources;
 import org.apache.ibatis.jdbc.ScriptRunner;
 import org.apache.ibatis.jdbc.SqlRunner;
-import org.springframework.core.io.ClassPathResource;
 
 import javax.sql.DataSource;
 import java.io.*;
@@ -126,7 +122,7 @@ public class DdlHelper {
     }
 
     public static InputStream getInputStream(String path) throws Exception {
-        return new ClassPathResource(path).getInputStream();
+        return CompatibleHelper.getCompatibleSet().getInputStream(path);
     }
 
     protected static String getNowTime() {

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

@@ -0,0 +1,128 @@
+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.toolkit.MybatisUtils;
+import com.baomidou.mybatisplus.core.toolkit.reflect.GenericTypeUtils;
+import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
+import org.apache.ibatis.logging.Log;
+import org.apache.ibatis.logging.LogFactory;
+import org.apache.ibatis.session.SqlSession;
+import org.apache.ibatis.session.SqlSessionFactory;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
+
+public abstract class AbstractRepository<M extends BaseMapper<T>, T>  implements IRepository<T> {
+
+    protected final Log log = LogFactory.getLog(getClass());
+
+    /**
+     * @see #getEntityClass()
+     */
+    private Class<T> entityClass;
+
+    @Override
+    public Class<T> getEntityClass() {
+        if(this.entityClass == null) {
+            this.entityClass = (Class<T>) GenericTypeUtils.resolveTypeArguments(this.getMapperClass(), BaseMapper.class)[0];
+        }
+        return this.entityClass;
+    }
+
+    /**
+     *  @see #getMapperClass()
+     */
+    private Class<M> mapperClass;
+
+    private volatile SqlSessionFactory sqlSessionFactory;
+
+    protected SqlSessionFactory getSqlSessionFactory() {
+        if (this.sqlSessionFactory == null) {
+            MybatisMapperProxy<?> mybatisMapperProxy = MybatisUtils.getMybatisMapperProxy(this.getBaseMapper());
+            this.sqlSessionFactory = MybatisUtils.getSqlSessionFactory(mybatisMapperProxy);
+        }
+        return this.sqlSessionFactory;
+    }
+
+    /**
+     * @return baseMapper 真实类型
+     * @since 3.5.7
+     */
+    public Class<M> getMapperClass() {
+        if (this.mapperClass == null) {
+            MybatisMapperProxy<?> mybatisMapperProxy = MybatisUtils.getMybatisMapperProxy(this.getBaseMapper());
+            this.mapperClass = (Class<M>) mybatisMapperProxy.getMapperInterface();
+        }
+        return this.mapperClass;
+    }
+
+    /**
+     * TableId 注解存在更新记录,否插入一条记录
+     *
+     * @param entity 实体对象
+     * @return boolean
+     */
+    @Override
+    public boolean saveOrUpdate(T entity) {
+        return getBaseMapper().insertOrUpdate(entity);
+    }
+
+    @Override
+    public T getOne(Wrapper<T> queryWrapper, boolean throwEx) {
+        return getBaseMapper().selectOne(queryWrapper, throwEx);
+    }
+
+    @Override
+    public Optional<T> getOneOpt(Wrapper<T> queryWrapper, boolean throwEx) {
+        return Optional.ofNullable(getBaseMapper().selectOne(queryWrapper, throwEx));
+    }
+
+    @Override
+    public Map<String, Object> getMap(Wrapper<T> queryWrapper) {
+        return SqlHelper.getObject(log, getBaseMapper().selectMaps(queryWrapper));
+    }
+
+    @Override
+    public <V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper) {
+        return SqlHelper.getObject(log, listObjs(queryWrapper, mapper));
+    }
+
+    /**
+     * 执行批量操作
+     *
+     * @param list      数据集合
+     * @param batchSize 批量大小
+     * @param consumer  执行方法
+     * @param <E>       泛型
+     * @return 操作结果
+     * @since 3.3.1
+     */
+    protected <E> boolean executeBatch(Collection<E> list, int batchSize, BiConsumer<SqlSession, E> consumer) {
+        return SqlHelper.executeBatch(getSqlSessionFactory(), this.log, list, batchSize, consumer);
+    }
+
+    /**
+     * 执行批量操作(默认批次提交数量{@link IRepository#DEFAULT_BATCH_SIZE})
+     *
+     * @param list     数据集合
+     * @param consumer 执行方法
+     * @param <E>      泛型
+     * @return 操作结果
+     * @since 3.3.1
+     */
+    protected <E> boolean executeBatch(Collection<E> list, BiConsumer<SqlSession, E> consumer) {
+        return executeBatch(list, DEFAULT_BATCH_SIZE, consumer);
+    }
+
+    @Override
+    public boolean removeById(Serializable id, boolean useFill) {
+        return SqlHelper.retBool(getBaseMapper().deleteById(id, useFill));
+    }
+
+}

+ 9 - 131
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/service/IService.java → mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/repository/IRepository.java

@@ -1,19 +1,4 @@
-/*
- * Copyright (c) 2011-2024, 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.service;
+package com.baomidou.mybatisplus.extension.repository;
 
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
@@ -22,30 +7,21 @@ import com.baomidou.mybatisplus.core.toolkit.Assert;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.core.toolkit.Constants;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
-import com.baomidou.mybatisplus.extension.conditions.query.ChainQuery;
 import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
 import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper;
-import com.baomidou.mybatisplus.extension.conditions.update.ChainUpdate;
 import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
 import com.baomidou.mybatisplus.extension.conditions.update.UpdateChainWrapper;
 import com.baomidou.mybatisplus.extension.kotlin.KtQueryChainWrapper;
 import com.baomidou.mybatisplus.extension.kotlin.KtUpdateChainWrapper;
 import com.baomidou.mybatisplus.extension.toolkit.ChainWrappers;
 import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
-import org.springframework.transaction.annotation.Transactional;
 
 import java.io.Serializable;
 import java.util.*;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
-/**
- * 顶级 Service
- *
- * @author hubin
- * @since 2018-06-23
- */
-public interface IService<T> {
+public interface IRepository<T> {
 
     /**
      * 默认批次提交数量
@@ -61,16 +37,6 @@ public interface IService<T> {
         return SqlHelper.retBool(getBaseMapper().insert(entity));
     }
 
-    /**
-     * 插入(批量)
-     *
-     * @param entityList 实体对象集合
-     */
-    @Transactional(rollbackFor = Exception.class)
-    default boolean saveBatch(Collection<T> entityList) {
-        return saveBatch(entityList, DEFAULT_BATCH_SIZE);
-    }
-
     /**
      * 插入(批量)
      *
@@ -79,16 +45,6 @@ public interface IService<T> {
      */
     boolean saveBatch(Collection<T> entityList, int batchSize);
 
-    /**
-     * 批量修改插入
-     *
-     * @param entityList 实体对象集合
-     */
-    @Transactional(rollbackFor = Exception.class)
-    default boolean saveOrUpdateBatch(Collection<T> entityList) {
-        return saveOrUpdateBatch(entityList, DEFAULT_BATCH_SIZE);
-    }
-
     /**
      * 批量修改插入
      *
@@ -174,59 +130,6 @@ public interface IService<T> {
         return SqlHelper.retBool(getBaseMapper().deleteByIds(list, useFill));
     }
 
-    /**
-     * 批量删除(jdbc批量提交)
-     *
-     * @param list 主键ID或实体列表(主键ID类型必须与实体类型字段保持一致)
-     * @return 删除结果
-     * @since 3.5.0
-     */
-    @Transactional(rollbackFor = Exception.class)
-    default boolean removeBatchByIds(Collection<?> list) {
-        return removeBatchByIds(list, DEFAULT_BATCH_SIZE);
-    }
-
-    /**
-     * 批量删除(jdbc批量提交)
-     *
-     * @param list    主键ID或实体列表(主键ID类型必须与实体类型字段保持一致)
-     * @param useFill 是否启用填充(为true的情况,会将入参转换实体进行delete删除)
-     * @return 删除结果
-     * @since 3.5.0
-     */
-    default boolean removeBatchByIds(Collection<?> list, boolean useFill) {
-        return removeBatchByIds(list, DEFAULT_BATCH_SIZE, useFill);
-    }
-
-    /**
-     * 批量删除(jdbc批量提交)
-     *
-     * @param list      主键ID或实体列表
-     * @param batchSize 批次大小
-     * @return 删除结果
-     * @since 3.5.0
-     * @deprecated 3.5.7 {@link #removeBatchByIds(Collection)}
-     */
-    @Deprecated
-    default boolean removeBatchByIds(Collection<?> list, int batchSize) {
-        throw new UnsupportedOperationException("不支持的方法!");
-    }
-
-    /**
-     * 批量删除(jdbc批量提交)
-     *
-     * @param list      主键ID或实体列表
-     * @param batchSize 批次大小
-     * @param useFill   是否启用填充(为true的情况,会将入参转换实体进行delete删除)
-     * @return 删除结果
-     * @since 3.5.0
-     * @deprecated 3.5.7 {@link #removeBatchByIds(Collection)}
-     */
-    @Deprecated
-    default boolean removeBatchByIds(Collection<?> list, int batchSize, boolean useFill) {
-        throw new UnsupportedOperationException("不支持的方法!");
-    }
-
     /**
      * 根据 ID 选择修改
      *
@@ -256,16 +159,6 @@ public interface IService<T> {
         return SqlHelper.retBool(getBaseMapper().update(entity, updateWrapper));
     }
 
-    /**
-     * 根据ID 批量更新
-     *
-     * @param entityList 实体对象集合
-     */
-    @Transactional(rollbackFor = Exception.class)
-    default boolean updateBatchById(Collection<T> entityList) {
-        return updateBatchById(entityList, DEFAULT_BATCH_SIZE);
-    }
-
     /**
      * 根据ID 批量更新
      *
@@ -570,20 +463,24 @@ public interface IService<T> {
      */
     Class<T> getEntityClass();
 
-    /**
+    /*
      * 以下的方法使用介绍:
-     *
+     * <p>
      * 一. 名称介绍
      * 1. 方法名带有 query 的为对数据的查询操作, 方法名带有 update 的为对数据的修改操作
      * 2. 方法名带有 lambda 的为内部方法入参 column 支持函数式的
+     * </p>
+     * <p>
      * 二. 支持介绍
-     *
      * 1. 方法名带有 query 的支持以 {@link ChainQuery} 内部的方法名结尾进行数据查询操作
      * 2. 方法名带有 update 的支持以 {@link ChainUpdate} 内部的方法名为结尾进行数据修改操作
+     * </p>
      *
+     * <p>
      * 三. 使用示例,只用不带 lambda 的方法各展示一个例子,其他类推
      * 1. 根据条件获取一条数据: `query().eq("column", value).one()`
      * 2. 根据条件删除一条数据: `update().eq("column", value).remove()`
+     * </p>
      *
      */
 
@@ -655,23 +552,4 @@ public interface IService<T> {
     default LambdaUpdateChainWrapper<T> lambdaUpdate() {
         return ChainWrappers.lambdaUpdateChain(getBaseMapper());
     }
-
-    /**
-     * <p>
-     * 根据updateWrapper尝试更新,否继续执行saveOrUpdate(T)方法
-     * 此次修改主要是减少了此项业务代码的代码量(存在性验证之后的saveOrUpdate操作)
-     * </p>
-     * <p>
-     * 该方法不推荐在多线程并发下使用,并发可能存在间隙锁的问题,可以采用先查询后判断是否更新或保存。
-     * </p>
-     * <p>
-     * 该方法存在安全隐患将在后续大版本删除
-     * </p>
-     *
-     * @param entity 实体对象
-     */
-    @Deprecated
-    default boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper) {
-        return update(entity, updateWrapper) || saveOrUpdate(entity);
-    }
 }

+ 0 - 310
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/service/impl/ServiceImpl.java

@@ -1,310 +0,0 @@
-/*
- * Copyright (c) 2011-2024, 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.service.impl;
-
-import com.baomidou.mybatisplus.core.conditions.Wrapper;
-import com.baomidou.mybatisplus.core.enums.SqlMethod;
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-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 com.baomidou.mybatisplus.extension.service.IService;
-import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
-import org.apache.ibatis.binding.MapperMethod;
-import org.apache.ibatis.logging.Log;
-import org.apache.ibatis.logging.LogFactory;
-import org.apache.ibatis.session.ExecutorType;
-import org.apache.ibatis.session.SqlSession;
-import org.apache.ibatis.session.SqlSessionFactory;
-import org.mybatis.spring.SqlSessionUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.io.Serializable;
-import java.util.Collection;
-import java.util.Map;
-import java.util.Optional;
-import java.util.function.BiConsumer;
-import java.util.function.Consumer;
-import java.util.function.Function;
-
-/**
- * IService 实现类( 泛型:M 是 mapper 对象,T 是实体 )
- *
- * @author hubin
- * @since 2018-06-23
- */
-@SuppressWarnings("unchecked")
-public abstract class ServiceImpl<M extends BaseMapper<T>, T> implements IService<T> {
-
-    protected final Log log = LogFactory.getLog(getClass());
-
-    @Autowired
-    protected M baseMapper;
-
-    @Override
-    public M getBaseMapper() {
-        Assert.notNull(this.baseMapper, "baseMapper can not be null");
-        return this.baseMapper;
-    }
-
-    /**
-     * @see #getEntityClass()
-     */
-    private Class<T> entityClass;
-
-    @Override
-    public Class<T> getEntityClass() {
-        if(this.entityClass == null) {
-            this.entityClass = (Class<T>) GenericTypeUtils.resolveTypeArguments(this.getMapperClass(), BaseMapper.class)[0];
-        }
-        return this.entityClass;
-    }
-
-    /**
-     *  @see #currentMapperClass()
-     */
-    private Class<M> mapperClass;
-
-    private volatile SqlSessionFactory sqlSessionFactory;
-
-    protected SqlSessionFactory getSqlSessionFactory() {
-        if (this.sqlSessionFactory == null) {
-            MybatisMapperProxy<?> mybatisMapperProxy = MybatisUtils.getMybatisMapperProxy(this.getBaseMapper());
-            this.sqlSessionFactory = MybatisUtils.getSqlSessionFactory(mybatisMapperProxy);
-        }
-        return this.sqlSessionFactory;
-    }
-
-    /**
-     * 判断数据库操作是否成功
-     *
-     * @param result 数据库操作返回影响条数
-     * @return boolean
-     * @deprecated 3.3.1
-     */
-    @Deprecated
-    protected boolean retBool(Integer result) {
-        return SqlHelper.retBool(result);
-    }
-
-    /**
-     * @return baseMapper 真实类型
-     * @deprecated 3.5.7 {@link #getMapperClass()}
-     */
-    @Deprecated
-    protected Class<M> currentMapperClass() {
-        return this.getMapperClass();
-    }
-
-    /**
-     * @return baseMapper 真实类型
-     * @since 3.5.7
-     */
-    public Class<M> getMapperClass() {
-        if (this.mapperClass == null) {
-            MybatisMapperProxy<?> mybatisMapperProxy = MybatisUtils.getMybatisMapperProxy(this.getBaseMapper());
-            this.mapperClass = (Class<M>) mybatisMapperProxy.getMapperInterface();
-        }
-        return this.mapperClass;
-    }
-
-    /**
-     * @return 实体类型
-     * @deprecated 3.5.7 {@link #getEntityClass()}
-     */
-    @Deprecated
-    protected Class<T> currentModelClass() {
-        return getEntityClass();
-    }
-
-
-    /**
-     * 批量操作 SqlSession
-     *
-     * @deprecated 3.3.0
-     */
-    @Deprecated
-    protected SqlSession sqlSessionBatch() {
-        return getSqlSessionFactory().openSession(ExecutorType.BATCH);
-    }
-
-    /**
-     * 释放sqlSession
-     *
-     * @param sqlSession session
-     * @deprecated 3.3.0
-     */
-    @Deprecated
-    protected void closeSqlSession(SqlSession sqlSession) {
-        SqlSessionUtils.closeSqlSession(sqlSession, getSqlSessionFactory());
-    }
-
-    /**
-     * 获取 SqlStatement
-     *
-     * @param sqlMethod ignore
-     * @return ignore
-     * @see #getSqlStatement(SqlMethod)
-     * @deprecated 3.4.0
-     */
-    @Deprecated
-    protected String sqlStatement(SqlMethod sqlMethod) {
-        return SqlHelper.table(getEntityClass()).getSqlStatement(sqlMethod.getMethod());
-    }
-
-    /**
-     * 批量插入
-     *
-     * @param entityList ignore
-     * @param batchSize  ignore
-     * @return ignore
-     */
-    @Transactional(rollbackFor = Exception.class)
-    @Override
-    public boolean saveBatch(Collection<T> entityList, int batchSize) {
-        String sqlStatement = getSqlStatement(SqlMethod.INSERT_ONE);
-        return executeBatch(entityList, batchSize, (sqlSession, entity) -> sqlSession.insert(sqlStatement, entity));
-    }
-
-    /**
-     * 获取mapperStatementId
-     *
-     * @param sqlMethod 方法名
-     * @return 命名id
-     * @since 3.4.0
-     */
-    protected String getSqlStatement(SqlMethod sqlMethod) {
-        return SqlHelper.getSqlStatement(this.currentMapperClass(), sqlMethod);
-    }
-
-    /**
-     * TableId 注解存在更新记录,否插入一条记录
-     *
-     * @param entity 实体对象
-     * @return boolean
-     */
-    @Override
-    public boolean saveOrUpdate(T entity) {
-        return getBaseMapper().insertOrUpdate(entity);
-    }
-
-    @Transactional(rollbackFor = Exception.class)
-    @Override
-    public boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize) {
-        TableInfo tableInfo = TableInfoHelper.getTableInfo(this.getEntityClass());
-        Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!");
-        String keyProperty = tableInfo.getKeyProperty();
-        Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!");
-        return SqlHelper.saveOrUpdateBatch(getSqlSessionFactory(), this.currentMapperClass(), this.log, entityList, batchSize, (sqlSession, entity) -> {
-            Object idVal = tableInfo.getPropertyValue(entity, keyProperty);
-            return StringUtils.checkValNull(idVal)
-                || CollectionUtils.isEmpty(sqlSession.selectList(getSqlStatement(SqlMethod.SELECT_BY_ID), entity));
-        }, (sqlSession, entity) -> {
-            MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
-            param.put(Constants.ENTITY, entity);
-            sqlSession.update(getSqlStatement(SqlMethod.UPDATE_BY_ID), param);
-        });
-    }
-
-    @Transactional(rollbackFor = Exception.class)
-    @Override
-    public boolean updateBatchById(Collection<T> entityList, int batchSize) {
-        String sqlStatement = getSqlStatement(SqlMethod.UPDATE_BY_ID);
-        return executeBatch(entityList, batchSize, (sqlSession, entity) -> {
-            MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
-            param.put(Constants.ENTITY, entity);
-            sqlSession.update(sqlStatement, param);
-        });
-    }
-
-    @Override
-    public T getOne(Wrapper<T> queryWrapper, boolean throwEx) {
-        return getBaseMapper().selectOne(queryWrapper, throwEx);
-    }
-
-    @Override
-    public Optional<T> getOneOpt(Wrapper<T> queryWrapper, boolean throwEx) {
-        return Optional.ofNullable(getBaseMapper().selectOne(queryWrapper, throwEx));
-    }
-
-    @Override
-    public Map<String, Object> getMap(Wrapper<T> queryWrapper) {
-        return SqlHelper.getObject(log, getBaseMapper().selectMaps(queryWrapper));
-    }
-
-    @Override
-    public <V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper) {
-        return SqlHelper.getObject(log, listObjs(queryWrapper, mapper));
-    }
-
-    /**
-     * 执行批量操作
-     *
-     * @param consumer consumer
-     * @since 3.3.0
-     * @deprecated 3.3.1 后面我打算移除掉 {@link #executeBatch(Collection, int, BiConsumer)} }.
-     */
-    @Deprecated
-    protected boolean executeBatch(Consumer<SqlSession> consumer) {
-        return SqlHelper.executeBatch(getSqlSessionFactory(), this.log, consumer);
-    }
-
-    /**
-     * 执行批量操作
-     *
-     * @param list      数据集合
-     * @param batchSize 批量大小
-     * @param consumer  执行方法
-     * @param <E>       泛型
-     * @return 操作结果
-     * @since 3.3.1
-     */
-    protected <E> boolean executeBatch(Collection<E> list, int batchSize, BiConsumer<SqlSession, E> consumer) {
-        return SqlHelper.executeBatch(getSqlSessionFactory(), this.log, list, batchSize, consumer);
-    }
-
-    /**
-     * 执行批量操作(默认批次提交数量{@link IService#DEFAULT_BATCH_SIZE})
-     *
-     * @param list     数据集合
-     * @param consumer 执行方法
-     * @param <E>      泛型
-     * @return 操作结果
-     * @since 3.3.1
-     */
-    protected <E> boolean executeBatch(Collection<E> list, BiConsumer<SqlSession, E> consumer) {
-        return executeBatch(list, DEFAULT_BATCH_SIZE, consumer);
-    }
-
-    @Override
-    public boolean removeById(Serializable id, boolean useFill) {
-        return SqlHelper.retBool(getBaseMapper().deleteById(id, useFill));
-    }
-
-    @Override
-    public boolean removeBatchByIds(Collection<?> list, int batchSize) {
-        return SqlHelper.retBool(getBaseMapper().deleteByIds(list));
-    }
-
-    @Override
-    public boolean removeBatchByIds(Collection<?> list, int batchSize, boolean useFill) {
-        return SqlHelper.retBool(getBaseMapper().deleteByIds(list, useFill));
-    }
-
-}

+ 8 - 46
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/toolkit/SqlHelper.java

@@ -21,18 +21,12 @@ 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 lombok.SneakyThrows;
-import org.apache.ibatis.exceptions.PersistenceException;
+import com.baomidou.mybatisplus.extension.compatible.CompatibleHelper;
 import org.apache.ibatis.executor.BatchResult;
 import org.apache.ibatis.logging.Log;
-import org.apache.ibatis.reflection.ExceptionUtil;
 import org.apache.ibatis.session.ExecutorType;
 import org.apache.ibatis.session.SqlSession;
 import org.apache.ibatis.session.SqlSessionFactory;
-import org.mybatis.spring.MyBatisExceptionTranslator;
-import org.mybatis.spring.SqlSessionHolder;
-import org.mybatis.spring.SqlSessionUtils;
-import org.springframework.transaction.support.TransactionSynchronizationManager;
 
 import java.sql.Statement;
 import java.util.Collection;
@@ -92,7 +86,7 @@ public final class SqlHelper {
      */
     @Deprecated
     public static SqlSession sqlSession(Class<?> clazz) {
-        return SqlSessionUtils.getSqlSession(GlobalConfigUtils.currentSessionFactory(clazz));
+        return CompatibleHelper.getCompatibleSet().getSqlSession(GlobalConfigUtils.currentSessionFactory(clazz));
     }
 
     /**
@@ -188,40 +182,8 @@ public final class SqlHelper {
         return executeBatch(sqlSessionFactory(entityClass), log, consumer);
     }
 
-    @SneakyThrows
     public static boolean executeBatch(SqlSessionFactory sqlSessionFactory, Log log, Consumer<SqlSession> consumer) {
-        SqlSessionHolder sqlSessionHolder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sqlSessionFactory);
-        boolean transaction = TransactionSynchronizationManager.isSynchronizationActive();
-        if (sqlSessionHolder != null) {
-            SqlSession sqlSession = sqlSessionHolder.getSqlSession();
-            //原生无法支持执行器切换,当存在批量操作时,会嵌套两个session的,优先commit上一个session
-            //按道理来说,这里的值应该一直为false。
-            sqlSession.commit(!transaction);
-        }
-        SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
-        if (!transaction) {
-            log.warn("SqlSession [" + sqlSession + "] Transaction not enabled");
-        }
-        try {
-            consumer.accept(sqlSession);
-            //非事务情况下,强制commit。
-            sqlSession.commit(!transaction);
-            return true;
-        } catch (Throwable t) {
-            sqlSession.rollback();
-            Throwable unwrapped = ExceptionUtil.unwrapThrowable(t);
-            if (unwrapped instanceof PersistenceException) {
-                MyBatisExceptionTranslator myBatisExceptionTranslator
-                    = new MyBatisExceptionTranslator(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(), true);
-                Throwable throwable = myBatisExceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
-                if (throwable != null) {
-                    throw throwable;
-                }
-            }
-            throw ExceptionUtils.mpe(unwrapped);
-        } finally {
-            sqlSession.close();
-        }
+        return CompatibleHelper.getCompatibleSet().executeBatch(sqlSessionFactory, log, consumer);
     }
 
     /**
@@ -318,9 +280,9 @@ public final class SqlHelper {
      * 例: {@code
      * SqlSession sqlSession = SqlHelper.sqlSession(entityClass);
      * try {
-     *     BaseMapper<User> userMapper = getMapper(User.class, sqlSession);
+     * BaseMapper<User> userMapper = getMapper(User.class, sqlSession);
      * } finally {
-     *     sqlSession.close();
+     * sqlSession.close();
      * }
      * }
      *
@@ -330,7 +292,7 @@ public final class SqlHelper {
      * @return Mapper
      */
     @SuppressWarnings("unchecked")
-    public static <T,M extends BaseMapper<T>> M getMapper(Class<T> entityClass, SqlSession sqlSession) {
+    public static <T, M extends BaseMapper<T>> M getMapper(Class<T> entityClass, SqlSession sqlSession) {
         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());
@@ -347,12 +309,12 @@ public final class SqlHelper {
      * @param <M>         Mapper类型
      * @return 返回lambda执行结果
      */
-    public static <T, R,M extends BaseMapper<T>> R execute(Class<T> entityClass, SFunction<M, R> sFunction) {
+    public static <T, R, M extends BaseMapper<T>> R execute(Class<T> entityClass, SFunction<M, R> sFunction) {
         SqlSession sqlSession = SqlHelper.sqlSession(entityClass);
         try {
             return sFunction.apply(SqlHelper.getMapper(entityClass, sqlSession));
         } finally {
-            SqlSessionUtils.closeSqlSession(sqlSession, GlobalConfigUtils.currentSessionFactory(entityClass));
+            CompatibleHelper.getCompatibleSet().closeSqlSession(sqlSession, GlobalConfigUtils.currentSessionFactory(entityClass));
         }
     }
 }

+ 1 - 2
mybatis-plus-generator/src/main/java/com/baomidou/mybatisplus/generator/config/po/TableInfo.java

@@ -17,7 +17,6 @@ package com.baomidou.mybatisplus.generator.config.po;
 
 import com.baomidou.mybatisplus.annotation.*;
 import com.baomidou.mybatisplus.core.toolkit.StringUtils;
-import com.baomidou.mybatisplus.extension.activerecord.Model;
 import com.baomidou.mybatisplus.generator.config.GlobalConfig;
 import com.baomidou.mybatisplus.generator.config.StrategyConfig;
 import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
@@ -229,7 +228,7 @@ public class TableInfo {
         } else {
             if (entity.isActiveRecord()) {
                 // 无父类开启 AR 模式
-                this.importPackages.add(Model.class.getCanonicalName());
+                this.importPackages.add("com.baomidou.mybatisplus.extension.activerecord.Model");
             }
         }
         if (entity.isSerialVersionUID() || entity.isActiveRecord()) {

+ 17 - 0
mybatis-plus-solon-plugin/build.gradle

@@ -0,0 +1,17 @@
+apply plugin: 'kotlin'
+
+compileKotlin{
+    kotlinOptions.jvmTarget = "1.8"
+}
+
+dependencies {
+    api project(":mybatis-plus-extension")
+    api "org.noear:mybatis-solon-plugin:3.0.0"
+    api "org.noear:solon-aot:3.0.0"
+    testImplementation "org.noear:solon-test:3.0.0"
+    testImplementation "io.github.classgraph:classgraph:4.8.176"
+    testImplementation "com.zaxxer:HikariCP:4.0.3"
+    testImplementation "${lib.h2}"
+    testImplementation "${lib.mysql}"
+    testImplementation "${lib.'logback-classic'}"
+}

+ 33 - 0
mybatis-plus-solon-plugin/src/main/java/com/baomidou/mybatisplus/core/override/SolonMybatisMapperProxy.java

@@ -0,0 +1,33 @@
+package com.baomidou.mybatisplus.core.override;
+
+import org.apache.ibatis.session.SqlSession;
+import org.apache.ibatis.session.SqlSessionFactory;
+
+import java.lang.reflect.Method;
+
+public class SolonMybatisMapperProxy<T> extends MybatisMapperProxy<T> {
+
+    private final SqlSessionFactory factory;
+    private final Class<T> mapperInterface;
+    private final SqlSession sqlSession;
+
+    public SolonMybatisMapperProxy(SqlSessionFactory sqlSessionFactory, SqlSession sqlSession, Class<T> mapperInterface) {
+        super(null, mapperInterface, null);
+        this.factory = sqlSessionFactory;
+        this.sqlSession = sqlSession;
+        this.mapperInterface = mapperInterface;
+    }
+
+    @Override
+    public SqlSession getSqlSession() {
+        return sqlSession;
+    }
+
+    @Override
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        try (SqlSession session = factory.openSession(true)) {
+            Object mapper = session.getMapper(mapperInterface);
+            return method.invoke(mapper, args);
+        }
+    }
+}

+ 39 - 0
mybatis-plus-solon-plugin/src/main/java/com/baomidou/mybatisplus/extension/activerecord/Model.java

@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2011-2024, 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.activerecord;
+
+import com.baomidou.mybatisplus.extension.toolkit.SqlRunner;
+
+/**
+ * ActiveRecord 模式 CRUD
+ * <p>
+ * 必须存在对应的原始mapper并继承baseMapper并且可以使用的前提下
+ * 才能使用此 AR 模式 !!!
+ * </p>
+ *
+ * @param <T>
+ * @author hubin
+ * @since 2016-11-06
+ */
+public abstract class Model<T extends Model<?>> extends AbstractModel<T> {
+
+    /**
+     * 执行 SQL
+     */
+    public SqlRunner sql() {
+        return new SqlRunner(this.entityClass);
+    }
+}

+ 80 - 0
mybatis-plus-solon-plugin/src/main/java/com/baomidou/mybatisplus/extension/compatible/SolonCompatibleSet.java

@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2011-2024, 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.compatible;
+
+import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
+import org.apache.ibatis.logging.Log;
+import org.apache.ibatis.reflection.ExceptionUtil;
+import org.apache.ibatis.session.ExecutorType;
+import org.apache.ibatis.session.SqlSession;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.noear.solon.core.util.GenericUtil;
+import org.noear.solon.core.util.ResourceUtil;
+import org.noear.solon.data.tran.TranUtils;
+
+import java.io.InputStream;
+import java.util.function.Consumer;
+
+/**
+ * spring 兼容方法集接口实现类
+ */
+public class SolonCompatibleSet implements CompatibleSet {
+
+    @Override
+    public SqlSession getSqlSession(SqlSessionFactory sessionFactory) {
+        return sessionFactory.openSession();
+    }
+
+    @Override
+    public void closeSqlSession(SqlSession sqlSession, SqlSessionFactory sqlSessionFactory) {
+        if (sqlSession != null) {
+            sqlSession.close();
+        }
+    }
+
+    @Override
+    public boolean executeBatch(SqlSessionFactory sqlSessionFactory, Log log, Consumer<SqlSession> consumer) {
+        boolean transaction = TranUtils.inTrans();
+        SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
+        if (!transaction) {
+            log.warn("SqlSession [" + sqlSession + "] Transaction not enabled");
+        }
+        try {
+            consumer.accept(sqlSession);
+            //非事务情况下,强制commit。
+            sqlSession.commit(!transaction);
+            return true;
+        } catch (RuntimeException t) {
+            throw t;
+        } catch (Throwable t) {
+            sqlSession.rollback();
+            Throwable unwrapped = ExceptionUtil.unwrapThrowable(t);
+            if (unwrapped instanceof RuntimeException) {
+                throw (RuntimeException) unwrapped;
+            } else {
+                throw ExceptionUtils.mpe(unwrapped);
+            }
+        } finally {
+            sqlSession.close();
+        }
+    }
+
+    @Override
+    public InputStream getInputStream(String path) throws Exception {
+        return ResourceUtil.findResource(path).openStream();
+    }
+
+}

+ 45 - 0
mybatis-plus-solon-plugin/src/main/java/com/baomidou/mybatisplus/extension/ddl/SimpleDdl.java

@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2011-2024, 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.ddl;
+
+import org.noear.solon.annotation.Inject;
+
+import javax.sql.DataSource;
+import java.util.List;
+import java.util.function.Consumer;
+
+/**
+ * 非多数据源 DDL 实现
+ *
+ * @author hubin
+ * @since 2021-09-23
+ */
+public class SimpleDdl implements IDdl {
+
+    @Inject
+    private DataSource dataSource;
+
+    @Override
+    public void runScript(Consumer<DataSource> consumer) {
+        consumer.accept(dataSource);
+    }
+
+    @Override
+    public List<String> getSqlFiles() {
+        return null;
+    }
+
+}

+ 103 - 0
mybatis-plus-solon-plugin/src/main/java/com/baomidou/mybatisplus/extension/repository/CrudRepository.java

@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2011-2024, 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.repository;
+
+import com.baomidou.mybatisplus.core.enums.SqlMethod;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.TableInfo;
+import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
+import com.baomidou.mybatisplus.core.toolkit.Assert;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
+import org.apache.ibatis.binding.MapperMethod;
+import org.noear.solon.annotation.Inject;
+import org.noear.solon.data.annotation.Tran;
+
+import java.util.Collection;
+
+/**
+ * IService 实现类( 泛型:M 是 mapper 对象,T 是实体 )
+ *
+ * @author hubin
+ * @since 2018-06-23
+ */
+public abstract class CrudRepository<M extends BaseMapper<T>, T> extends AbstractRepository<M, T> {
+
+    @Inject
+    protected M baseMapper;
+
+    @Override
+    public M getBaseMapper() {
+        Assert.notNull(this.baseMapper, "baseMapper can not be null");
+        return this.baseMapper;
+    }
+
+    /**
+     * 批量插入
+     *
+     * @param entityList ignore
+     * @param batchSize  ignore
+     * @return ignore
+     */
+    @Tran
+    @Override
+    public boolean saveBatch(Collection<T> entityList, int batchSize) {
+        String sqlStatement = getSqlStatement(SqlMethod.INSERT_ONE);
+        return executeBatch(entityList, batchSize, (sqlSession, entity) -> sqlSession.insert(sqlStatement, entity));
+    }
+
+    /**
+     * 获取mapperStatementId
+     *
+     * @param sqlMethod 方法名
+     * @return 命名id
+     * @since 3.4.0
+     */
+    protected String getSqlStatement(SqlMethod sqlMethod) {
+        return SqlHelper.getSqlStatement(this.getMapperClass(), sqlMethod);
+    }
+
+    @Tran
+    @Override
+    public boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize) {
+        TableInfo tableInfo = TableInfoHelper.getTableInfo(this.getEntityClass());
+        Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!");
+        String keyProperty = tableInfo.getKeyProperty();
+        Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!");
+        return SqlHelper.saveOrUpdateBatch(getSqlSessionFactory(), this.getMapperClass(), this.log, entityList, batchSize, (sqlSession, entity) -> {
+            Object idVal = tableInfo.getPropertyValue(entity, keyProperty);
+            return StringUtils.checkValNull(idVal)
+                || CollectionUtils.isEmpty(sqlSession.selectList(getSqlStatement(SqlMethod.SELECT_BY_ID), entity));
+        }, (sqlSession, entity) -> {
+            MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
+            param.put(Constants.ENTITY, entity);
+            sqlSession.update(getSqlStatement(SqlMethod.UPDATE_BY_ID), param);
+        });
+    }
+
+    @Tran
+    @Override
+    public boolean updateBatchById(Collection<T> entityList, int batchSize) {
+        String sqlStatement = getSqlStatement(SqlMethod.UPDATE_BY_ID);
+        return executeBatch(entityList, batchSize, (sqlSession, entity) -> {
+            MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
+            param.put(Constants.ENTITY, entity);
+            sqlSession.update(sqlStatement, param);
+        });
+    }
+}

+ 72 - 0
mybatis-plus-solon-plugin/src/main/java/com/baomidou/mybatisplus/extension/service/IService.java

@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2011-2024, 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.service;
+
+import com.baomidou.mybatisplus.extension.repository.IRepository;
+import org.noear.solon.data.annotation.Tran;
+
+import java.util.Collection;
+
+/**
+ * 顶级 Service
+ *
+ * @author hubin
+ * @since 2018-06-23
+ */
+public interface IService<T> extends IRepository<T> {
+
+    /**
+     * 插入(批量)
+     *
+     * @param entityList 实体对象集合
+     */
+    @Tran
+    default boolean saveBatch(Collection<T> entityList) {
+        return saveBatch(entityList, DEFAULT_BATCH_SIZE);
+    }
+
+    /**
+     * 批量修改插入
+     *
+     * @param entityList 实体对象集合
+     */
+    @Tran
+    default boolean saveOrUpdateBatch(Collection<T> entityList) {
+        return saveOrUpdateBatch(entityList, DEFAULT_BATCH_SIZE);
+    }
+
+    /**
+     * 批量删除(jdbc批量提交)
+     *
+     * @param list 主键ID或实体列表(主键ID类型必须与实体类型字段保持一致)
+     * @return 删除结果
+     * @since 3.5.0
+     */
+    @Tran
+    default boolean removeBatchByIds(Collection<?> list) {
+        return removeByIds(list);
+    }
+
+    /**
+     * 根据ID 批量更新
+     *
+     * @param entityList 实体对象集合
+     */
+    @Tran
+    default boolean updateBatchById(Collection<T> entityList) {
+        return updateBatchById(entityList, DEFAULT_BATCH_SIZE);
+    }
+}

+ 30 - 0
mybatis-plus-solon-plugin/src/main/java/com/baomidou/mybatisplus/extension/service/impl/ServiceImpl.java

@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2011-2024, 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.service.impl;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.repository.CrudRepository;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * IService 实现类( 泛型:M 是 mapper 对象,T 是实体 )
+ *
+ * @author hubin
+ * @since 2018-06-23
+ */
+public class ServiceImpl<M extends BaseMapper<T>, T> extends CrudRepository<M, T> implements IService<T> {
+
+}

+ 0 - 0
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/service/impl/package-info.java → mybatis-plus-solon-plugin/src/main/java/com/baomidou/mybatisplus/extension/service/impl/package-info.java


+ 0 - 0
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/service/package-info.java → mybatis-plus-solon-plugin/src/main/java/com/baomidou/mybatisplus/extension/service/package-info.java


+ 244 - 0
mybatis-plus-solon-plugin/src/main/java/com/baomidou/mybatisplus/extension/toolkit/SqlRunner.java

@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2011-2024, 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.toolkit;
+
+import com.baomidou.mybatisplus.core.assist.ISqlRunner;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import org.apache.ibatis.logging.Log;
+import org.apache.ibatis.logging.LogFactory;
+import org.apache.ibatis.session.SqlSession;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.noear.solon.data.annotation.Tran;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * SqlRunner 执行 SQL
+ *
+ * @author Caratacus
+ * @since 2016-12-11
+ */
+public class SqlRunner implements ISqlRunner {
+
+    // 单例Query
+    public static final SqlRunner DEFAULT = new SqlRunner();
+    private final Log log = LogFactory.getLog(SqlRunner.class);
+    private Class<?> clazz;
+
+    public SqlRunner() {
+    }
+
+    public SqlRunner(Class<?> clazz) {
+        this.clazz = clazz;
+    }
+
+    /**
+     * 获取默认的SqlQuery(适用于单库)
+     *
+     * @return ignore
+     */
+    public static SqlRunner db() {
+        return DEFAULT;
+    }
+
+    /**
+     * 根据当前class对象获取SqlQuery(适用于多库)
+     *
+     * @param clazz ignore
+     * @return ignore
+     */
+    public static SqlRunner db(Class<?> clazz) {
+        return new SqlRunner(clazz);
+    }
+
+    @Tran
+    @Override
+    public boolean insert(String sql, Object... args) {
+        SqlSession sqlSession = sqlSession();
+        try {
+            return SqlHelper.retBool(sqlSession.insert(INSERT, sqlMap(sql, args)));
+        } finally {
+            closeSqlSession(sqlSession);
+        }
+    }
+
+    @Tran
+    @Override
+    public boolean delete(String sql, Object... args) {
+        SqlSession sqlSession = sqlSession();
+        try {
+            return SqlHelper.retBool(sqlSession.delete(DELETE, sqlMap(sql, args)));
+        } finally {
+            closeSqlSession(sqlSession);
+        }
+    }
+
+    /**
+     * 获取sqlMap参数
+     *
+     * @param sql  指定参数的格式: {0}, {1}
+     * @param args 仅支持String
+     * @return ignore
+     */
+    private Map<String, String> sqlMap(String sql, Object... args) {
+        Map<String, String> sqlMap = CollectionUtils.newHashMapWithExpectedSize(1);
+        sqlMap.put(SQL, StringUtils.sqlArgsFill(sql, args));
+        return sqlMap;
+    }
+
+    /**
+     * 获取sqlMap参数
+     *
+     * @param sql  指定参数的格式: {0}, {1}
+     * @param page 分页模型
+     * @param args 仅支持String
+     * @return ignore
+     */
+    private Map<String, Object> sqlMap(String sql, IPage<?> page, Object... args) {
+        Map<String, Object> sqlMap = CollectionUtils.newHashMapWithExpectedSize(2);
+        sqlMap.put(PAGE, page);
+        sqlMap.put(SQL, StringUtils.sqlArgsFill(sql, args));
+        return sqlMap;
+    }
+
+    @Tran
+    @Override
+    public boolean update(String sql, Object... args) {
+        SqlSession sqlSession = sqlSession();
+        try {
+            return SqlHelper.retBool(sqlSession.update(UPDATE, sqlMap(sql, args)));
+        } finally {
+            closeSqlSession(sqlSession);
+        }
+    }
+
+    /**
+     * 根据sql查询Map结果集
+     * <p>SqlRunner.db().selectList("select * from tbl_user where name={0}", "Caratacus")</p>
+     *
+     * @param sql  sql语句,可添加参数,格式:{0},{1}
+     * @param args 只接受String格式
+     * @return ignore
+     */
+    @Override
+    public List<Map<String, Object>> selectList(String sql, Object... args) {
+        SqlSession sqlSession = sqlSession();
+        try {
+            return sqlSession.selectList(SELECT_LIST, sqlMap(sql, args));
+        } finally {
+            closeSqlSession(sqlSession);
+        }
+    }
+
+    /**
+     * 根据sql查询一个字段值的结果集
+     * <p>注意:该方法只会返回一个字段的值, 如果需要多字段,请参考{@code selectList()}</p>
+     *
+     * @param sql  sql语句,可添加参数,格式:{0},{1}
+     * @param args 只接受String格式
+     * @return ignore
+     */
+    @Override
+    public List<Object> selectObjs(String sql, Object... args) {
+        SqlSession sqlSession = sqlSession();
+        try {
+            return sqlSession.selectList(SELECT_OBJS, sqlMap(sql, args));
+        } finally {
+            closeSqlSession(sqlSession);
+        }
+    }
+
+    /**
+     * 根据sql查询一个字段值的一条结果
+     * <p>注意:该方法只会返回一个字段的值, 如果需要多字段,请参考{@code selectOne()}</p>
+     *
+     * @param sql  sql语句,可添加参数,格式:{0},{1}
+     * @param args 只接受String格式
+     * @return ignore
+     */
+    @Override
+    public Object selectObj(String sql, Object... args) {
+        return SqlHelper.getObject(log, selectObjs(sql, args));
+    }
+
+    @Override
+    public long selectCount(String sql, Object... args) {
+        SqlSession sqlSession = sqlSession();
+        try {
+            return SqlHelper.retCount(sqlSession.<Long>selectOne(COUNT, sqlMap(sql, args)));
+        } finally {
+            closeSqlSession(sqlSession);
+        }
+    }
+
+    @Override
+    public Map<String, Object> selectOne(String sql, Object... args) {
+        return SqlHelper.getObject(log, selectList(sql, args));
+    }
+
+    @Override
+    public <E extends IPage<Map<String, Object>>> E selectPage(E page, String sql, Object... args) {
+        if (null == page) {
+            return null;
+        }
+        SqlSession sqlSession = sqlSession();
+        try {
+            page.setRecords(sqlSession.selectList(SELECT_LIST, sqlMap(sql, page, args)));
+        } finally {
+            closeSqlSession(sqlSession);
+        }
+        return page;
+    }
+
+    /**
+     * 获取Session 默认自动提交
+     */
+    private SqlSession sqlSession() {
+        return getSqlSessionFactory().openSession();
+    }
+
+    /**
+     * 释放sqlSession
+     *
+     * @param sqlSession session
+     */
+    private void closeSqlSession(SqlSession sqlSession) {
+        if (sqlSession != null) {
+            sqlSession.close();
+        }
+    }
+
+    /**
+     * 获取SqlSessionFactory
+     */
+    private SqlSessionFactory getSqlSessionFactory() {
+        return Optional.ofNullable(clazz).map(GlobalConfigUtils::currentSessionFactory).orElse(SqlHelper.FACTORY);
+    }
+
+    /**
+     * @deprecated 3.5.3.2
+     */
+    @Deprecated
+    public void close() {
+
+    }
+
+}

+ 24 - 0
mybatis-plus-solon-plugin/src/main/java/com/baomidou/mybatisplus/solon/integration/MybatisAdapterFactoryPlus.java

@@ -0,0 +1,24 @@
+package com.baomidou.mybatisplus.solon.integration;
+
+import org.apache.ibatis.solon.MybatisAdapter;
+import org.apache.ibatis.solon.MybatisAdapterFactory;
+import org.noear.solon.core.BeanWrap;
+import org.noear.solon.core.Props;
+
+/**
+ * 适配器工厂 for mybatis-plus
+ *
+ * @author noear, iYarnFog
+ * @since 1.5
+ */
+public class MybatisAdapterFactoryPlus implements MybatisAdapterFactory {
+    @Override
+    public MybatisAdapter create(BeanWrap dsWrap) {
+        return new MybatisAdapterPlus(dsWrap);
+    }
+
+    @Override
+    public MybatisAdapter create(BeanWrap dsWrap, Props dsProps) {
+        return new MybatisAdapterPlus(dsWrap, dsProps);
+    }
+}

+ 146 - 0
mybatis-plus-solon-plugin/src/main/java/com/baomidou/mybatisplus/solon/integration/MybatisAdapterPlus.java

@@ -0,0 +1,146 @@
+package com.baomidou.mybatisplus.solon.integration;
+
+import com.baomidou.mybatisplus.core.MybatisConfiguration;
+import com.baomidou.mybatisplus.core.MybatisSqlSessionFactoryBuilder;
+import com.baomidou.mybatisplus.core.config.GlobalConfig;
+import com.baomidou.mybatisplus.core.override.SolonMybatisMapperProxy;
+import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils;
+import org.apache.ibatis.mapping.Environment;
+import org.apache.ibatis.session.SqlSession;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.apache.ibatis.solon.integration.MybatisAdapterDefault;
+import org.noear.solon.Utils;
+import org.noear.solon.core.BeanWrap;
+import org.noear.solon.core.Props;
+import org.noear.solon.core.VarHolder;
+
+import java.lang.reflect.Proxy;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 适配器 for mybatis-plus
+ * <p>
+ * 1.提供 mapperScan 能力
+ * 2.生成 factory 的能力
+ *
+ * @author noear, iYarnFog
+ * @since 1.5
+ */
+public class MybatisAdapterPlus extends MybatisAdapterDefault {
+
+    MybatisSqlSessionFactoryBuilder factoryBuilderPlus;
+    GlobalConfig globalConfig;
+    SqlSession sqlSession;
+    Map<Class<?>, Object> mapperCached = new HashMap<>();
+
+    /**
+     * 构建Sql工厂适配器,使用默认的 typeAliases 和 mappers 配置
+     */
+    protected MybatisAdapterPlus(BeanWrap dsWrap) {
+        super(dsWrap);
+
+        this.factoryBuilderPlus = new MybatisSqlSessionFactoryBuilder();
+
+        dsWrap.context().getBeanAsync(MybatisSqlSessionFactoryBuilder.class, bean -> {
+            factoryBuilderPlus = bean;
+        });
+    }
+
+    /**
+     * 构建Sql工厂适配器,使用属性配置
+     */
+    protected MybatisAdapterPlus(BeanWrap dsWrap, Props dsProps) {
+        super(dsWrap, dsProps);
+
+        this.factoryBuilderPlus = new MybatisSqlSessionFactoryBuilder();
+
+        dsWrap.context().getBeanAsync(MybatisSqlSessionFactoryBuilder.class, bean -> {
+            factoryBuilderPlus = bean;
+        });
+    }
+
+    /**
+     * 初始化配置
+     */
+    @Override
+    protected void initConfiguration(Environment environment) {
+        //for configuration section
+        config = new MybatisConfiguration(environment);
+
+        Props cfgProps = dsProps.getProp("configuration");
+        if (cfgProps.size() > 0) {
+            Utils.injectProperties(config, cfgProps);
+        }
+
+
+        //for globalConfig section
+        globalConfig = new GlobalConfig().setDbConfig(new GlobalConfig.DbConfig());
+
+        Props globalProps = dsProps.getProp("globalConfig");
+        if (globalProps.size() > 0) {
+            //尝试配置注入
+            Utils.injectProperties(globalConfig, globalProps);
+        }
+
+        GlobalConfigUtils.setGlobalConfig(config, globalConfig);
+    }
+
+    /**
+     * 获取会话工厂
+     */
+    @Override
+    public SqlSessionFactory getFactory() {
+        if (factory == null) {
+            factory = factoryBuilderPlus.build(getConfiguration());
+        }
+
+        return factory;
+    }
+
+    public SqlSession getSession() {
+        if (sqlSession == null) {
+            sqlSession = new SolonSqlSession(getFactory());
+        }
+        return sqlSession;
+    }
+
+    @Override
+    public <T> T getMapper(Class<T> mapperClz) {
+        Object mapper = mapperCached.get(mapperClz);
+
+        if (mapper == null) {
+            synchronized (mapperClz) {
+                mapper = mapperCached.get(mapperClz);
+                if (mapper == null) {
+                    SolonMybatisMapperProxy<T> tMybatisMapperProxy = new SolonMybatisMapperProxy<>(getFactory(), getSession(), mapperClz);
+                    mapper = Proxy.newProxyInstance(
+                            mapperClz.getClassLoader(),
+                            new Class[]{mapperClz},
+                            tMybatisMapperProxy);
+                    mapperCached.put(mapperClz, mapper);
+                }
+            }
+        }
+
+        return (T) mapper;
+    }
+
+    /**
+     * 获取全局配置
+     */
+    public GlobalConfig getGlobalConfig() {
+        return globalConfig;
+    }
+
+    @Override
+    public void injectTo(VarHolder varH) {
+        super.injectTo(varH);
+
+        //@Db("db1") SqlSessionFactory factory;
+        if (GlobalConfig.class.isAssignableFrom(varH.getType())) {
+            varH.setValue(this.getGlobalConfig());
+            return;
+        }
+    }
+}

+ 209 - 0
mybatis-plus-solon-plugin/src/main/java/com/baomidou/mybatisplus/solon/integration/SolonSqlSession.java

@@ -0,0 +1,209 @@
+package com.baomidou.mybatisplus.solon.integration;
+
+import org.apache.ibatis.cursor.Cursor;
+import org.apache.ibatis.executor.BatchResult;
+import org.apache.ibatis.reflection.ExceptionUtil;
+import org.apache.ibatis.session.Configuration;
+import org.apache.ibatis.session.ResultHandler;
+import org.apache.ibatis.session.RowBounds;
+import org.apache.ibatis.session.SqlSession;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.noear.solon.data.tran.TranUtils;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.sql.Connection;
+import java.util.List;
+import java.util.Map;
+
+public class SolonSqlSession implements SqlSession {
+
+    private final SqlSessionFactory sqlSessionFactory;
+    private final SqlSession sqlSessionProxy;
+
+    public SolonSqlSession(SqlSessionFactory sqlSessionFactory) {
+        this.sqlSessionFactory = sqlSessionFactory;
+        this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(), new Class[]{SqlSession.class}, new SqlSessionInterceptor());
+    }
+
+    public SqlSessionFactory getSqlSessionFactory() {
+        return this.sqlSessionFactory;
+    }
+
+    public SqlSession getSqlSessionProxy() {
+        return this.sqlSessionProxy;
+    }
+
+    @Override
+    public <T> T selectOne(String statement) {
+        return this.sqlSessionProxy.selectOne(statement);
+    }
+
+    @Override
+    public <T> T selectOne(String statement, Object parameter) {
+        return this.sqlSessionProxy.selectOne(statement, parameter);
+    }
+
+    @Override
+    public <K, V> Map<K, V> selectMap(String statement, String mapKey) {
+        return this.sqlSessionProxy.selectMap(statement, mapKey);
+    }
+
+    @Override
+    public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {
+        return this.sqlSessionProxy.selectMap(statement, parameter, mapKey);
+    }
+
+    @Override
+    public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
+        return this.sqlSessionProxy.selectMap(statement, parameter, mapKey, rowBounds);
+    }
+
+    @Override
+    public <T> Cursor<T> selectCursor(String statement) {
+        return this.sqlSessionProxy.selectCursor(statement);
+    }
+
+    @Override
+    public <T> Cursor<T> selectCursor(String statement, Object parameter) {
+        return this.sqlSessionProxy.selectCursor(statement, parameter);
+    }
+
+    @Override
+    public <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds) {
+        return this.sqlSessionProxy.selectCursor(statement, parameter, rowBounds);
+    }
+
+    @Override
+    public <E> List<E> selectList(String statement) {
+        return this.sqlSessionProxy.selectList(statement);
+    }
+
+    @Override
+    public <E> List<E> selectList(String statement, Object parameter) {
+        return this.sqlSessionProxy.selectList(statement, parameter);
+    }
+
+    @Override
+    public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
+        return this.sqlSessionProxy.selectList(statement, parameter, rowBounds);
+    }
+
+    @Override
+    public void select(String statement, ResultHandler handler) {
+        this.sqlSessionProxy.select(statement, handler);
+    }
+
+    @Override
+    public void select(String statement, Object parameter, ResultHandler handler) {
+        this.sqlSessionProxy.select(statement, parameter, handler);
+    }
+
+    @Override
+    public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
+        this.sqlSessionProxy.select(statement, parameter, rowBounds, handler);
+    }
+
+    @Override
+    public int insert(String statement) {
+        return this.sqlSessionProxy.insert(statement);
+    }
+
+    @Override
+    public int insert(String statement, Object parameter) {
+        return this.sqlSessionProxy.insert(statement, parameter);
+    }
+
+    @Override
+    public int update(String statement) {
+        return this.sqlSessionProxy.update(statement);
+    }
+
+    @Override
+    public int update(String statement, Object parameter) {
+        return this.sqlSessionProxy.update(statement, parameter);
+    }
+
+    @Override
+    public int delete(String statement) {
+        return this.sqlSessionProxy.delete(statement);
+    }
+
+    @Override
+    public int delete(String statement, Object parameter) {
+        return this.sqlSessionProxy.delete(statement, parameter);
+    }
+
+    @Override
+    public <T> T getMapper(Class<T> type) {
+        return this.getConfiguration().getMapper(type, this);
+    }
+
+    @Override
+    public void commit() {
+        throw new UnsupportedOperationException("Manual commit is not allowed over a Solon managed SqlSession");
+    }
+
+    @Override
+    public void commit(boolean force) {
+        throw new UnsupportedOperationException("Manual commit is not allowed over a Solon managed SqlSession");
+    }
+
+    @Override
+    public void rollback() {
+        throw new UnsupportedOperationException("Manual rollback is not allowed over a Solon managed SqlSession");
+    }
+
+    @Override
+    public void rollback(boolean force) {
+        throw new UnsupportedOperationException("Manual rollback is not allowed over a Solon managed SqlSession");
+    }
+
+    @Override
+    public void close() {
+        throw new UnsupportedOperationException("Manual close is not allowed over a Solon managed SqlSession");
+    }
+
+    @Override
+    public void clearCache() {
+        this.sqlSessionProxy.clearCache();
+    }
+
+    @Override
+    public Configuration getConfiguration() {
+        return this.sqlSessionFactory.getConfiguration();
+    }
+
+    @Override
+    public Connection getConnection() {
+        return this.sqlSessionProxy.getConnection();
+    }
+
+    @Override
+    public List<BatchResult> flushStatements() {
+        return this.sqlSessionProxy.flushStatements();
+    }
+
+    private class SqlSessionInterceptor implements InvocationHandler {
+        private SqlSessionInterceptor() {
+        }
+
+        @Override
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+            Object unwrapped;
+            try (SqlSession sqlSession = sqlSessionFactory.openSession(true)) {
+                Object result = method.invoke(sqlSession, args);
+                sqlSession.commit(!TranUtils.inTrans());
+                unwrapped = result;
+            } catch (Throwable var11) {
+                unwrapped = ExceptionUtil.unwrapThrowable(var11);
+                if (unwrapped instanceof RuntimeException) {
+                    throw (RuntimeException) unwrapped;
+                }
+                throw (Throwable) unwrapped;
+            }
+            return unwrapped;
+        }
+    }
+}

+ 39 - 0
mybatis-plus-solon-plugin/src/main/java/com/baomidou/mybatisplus/solon/integration/XPluginImpl.java

@@ -0,0 +1,39 @@
+package com.baomidou.mybatisplus.solon.integration;
+
+import com.baomidou.mybatisplus.core.toolkit.reflect.GenericTypeUtils;
+import com.baomidou.mybatisplus.extension.compatible.CompatibleHelper;
+import com.baomidou.mybatisplus.extension.compatible.SolonCompatibleSet;
+import com.baomidou.mybatisplus.solon.integration.aot.MybatisPlusRuntimeNativeRegistrar;
+import org.noear.solon.aot.RuntimeNativeRegistrar;
+import org.noear.solon.core.AppContext;
+import org.noear.solon.core.runtime.NativeDetector;
+import org.noear.solon.core.util.ClassUtil;
+import org.noear.solon.core.util.GenericUtil;
+import org.apache.ibatis.solon.integration.MybatisAdapterManager;
+import org.noear.solon.core.Plugin;
+
+/**
+ * @author noear
+ * @since 1.5
+ */
+public class XPluginImpl implements Plugin {
+
+    @Override
+    public void start(AppContext context) {
+        //
+        // 此插件的 solon.plugin.priority 会大于 mybatis-solon-plugin 的值
+        //
+        MybatisAdapterManager.setAdapterFactory(new MybatisAdapterFactoryPlus());
+
+        // 注入兼容配置
+        CompatibleHelper.setCompatibleSet(new SolonCompatibleSet());
+
+        // 提供反射处理类
+        GenericTypeUtils.setGenericTypeResolver((GenericUtil::resolveTypeArguments));
+
+        // aot
+        if (NativeDetector.isAotRuntime() && ClassUtil.hasClass(() -> RuntimeNativeRegistrar.class)) {
+            context.wrapAndPut(MybatisPlusRuntimeNativeRegistrar.class);
+        }
+    }
+}

+ 68 - 0
mybatis-plus-solon-plugin/src/main/java/com/baomidou/mybatisplus/solon/integration/aot/MybatisPlusRuntimeNativeRegistrar.java

@@ -0,0 +1,68 @@
+package com.baomidou.mybatisplus.solon.integration.aot;
+
+import com.baomidou.mybatisplus.core.MybatisConfiguration;
+import com.baomidou.mybatisplus.core.MybatisXMLLanguageDriver;
+import com.baomidou.mybatisplus.core.conditions.AbstractLambdaWrapper;
+import com.baomidou.mybatisplus.core.conditions.AbstractWrapper;
+import com.baomidou.mybatisplus.core.conditions.ISqlSegment;
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.conditions.interfaces.Compare;
+import com.baomidou.mybatisplus.core.conditions.interfaces.Func;
+import com.baomidou.mybatisplus.core.conditions.interfaces.Join;
+import com.baomidou.mybatisplus.core.conditions.interfaces.Nested;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.Query;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
+import org.noear.solon.aot.RuntimeNativeMetadata;
+import org.noear.solon.aot.RuntimeNativeRegistrar;
+import org.noear.solon.aot.hint.ExecutableMode;
+import org.noear.solon.aot.hint.MemberCategory;
+import org.noear.solon.core.AppContext;
+
+import java.lang.invoke.SerializedLambda;
+
+/**
+ * mybatis-plus aot 注册 native 元数据
+ *
+ * @author songyinyin
+ * @since 2.3
+ */
+public class MybatisPlusRuntimeNativeRegistrar implements RuntimeNativeRegistrar {
+
+    @Override
+    public void register(AppContext context, RuntimeNativeMetadata metadata) {
+        metadata.registerDefaultConstructor(MybatisXMLLanguageDriver.class);
+        metadata.registerReflection(MybatisConfiguration.class, MemberCategory.DECLARED_FIELDS, MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS);
+        metadata.registerAllDeclaredMethod(MybatisConfiguration.class, ExecutableMode.INVOKE);
+
+        metadata.registerReflection(AbstractLambdaWrapper.class, MemberCategory.DECLARED_FIELDS, MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS);
+
+        metadata.registerJdkProxy(AbstractWrapper.DoSomething.class);
+        metadata.registerReflection(AbstractWrapper.DoSomething.class);
+        metadata.registerReflection(AbstractWrapper.class, MemberCategory.DECLARED_FIELDS, MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS);
+        metadata.registerAllDeclaredMethod(AbstractWrapper.class, ExecutableMode.INVOKE);
+
+        metadata.registerReflection(ISqlSegment.class, MemberCategory.DECLARED_FIELDS, MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS);
+        metadata.registerReflection(Wrapper.class, MemberCategory.DECLARED_FIELDS, MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS);
+
+        metadata.registerAllDeclaredMethod(Wrapper.class, ExecutableMode.INVOKE);
+
+        metadata.registerReflection(Compare.class, MemberCategory.DECLARED_FIELDS, MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS);
+        metadata.registerReflection(Func.class, MemberCategory.DECLARED_FIELDS, MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS);
+        metadata.registerReflection(Join.class, MemberCategory.DECLARED_FIELDS, MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS);
+        metadata.registerReflection(Nested.class, MemberCategory.DECLARED_FIELDS, MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS);
+
+        metadata.registerReflection(LambdaQueryWrapper.class, MemberCategory.DECLARED_FIELDS, MemberCategory.INTROSPECT_PUBLIC_METHODS,
+                MemberCategory.INTROSPECT_PUBLIC_METHODS, MemberCategory.INTROSPECT_DECLARED_CONSTRUCTORS);
+        metadata.registerAllDeclaredMethod(LambdaQueryWrapper.class, ExecutableMode.INVOKE);
+
+        metadata.registerReflection(Query.class, MemberCategory.DECLARED_FIELDS, MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS);
+
+        metadata.registerAllDeclaredMethod(BaseMapper.class, ExecutableMode.INVOKE);
+
+        metadata.registerSerialization(SerializedLambda.class);
+        metadata.registerSerialization(SFunction.class);
+    }
+
+}

+ 2 - 0
mybatis-plus-solon-plugin/src/main/resources/META-INF/solon/mybatis-plus-solon-plugin.properties

@@ -0,0 +1,2 @@
+solon.plugin=com.baomidou.mybatisplus.solon.integration.XPluginImpl
+solon.plugin.priority=30

+ 50 - 0
mybatis-plus-solon-plugin/src/test/java/demo/Config.java

@@ -0,0 +1,50 @@
+package demo;
+
+import com.baomidou.mybatisplus.core.MybatisConfiguration;
+import com.baomidou.mybatisplus.core.MybatisSqlSessionFactoryBuilder;
+import com.baomidou.mybatisplus.core.config.GlobalConfig;
+import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
+import com.zaxxer.hikari.HikariDataSource;
+import demo.dso.MetaObjectHandlerImpl;
+import demo.dso.MybatisSqlSessionFactoryBuilderImpl;
+import okhttp3.Interceptor;
+import org.apache.ibatis.solon.annotation.Db;
+import org.noear.solon.Solon;
+import org.noear.solon.annotation.Bean;
+import org.noear.solon.annotation.Configuration;
+import org.noear.solon.annotation.Inject;
+
+import javax.sql.DataSource;
+
+@Configuration
+public class Config {
+    @Bean("db1")
+    public DataSource db1(@Inject("${dataSource.db1}") HikariDataSource hikariDataSource) {
+        return hikariDataSource;
+    }
+
+//    @Bean
+//    public Interceptor plusInterceptor() {
+//        MybatisPlusInterceptor plusInterceptor = new MybatisPlusInterceptor();
+//        plusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
+//        return plusInterceptor;
+//    }
+
+    @Bean
+    public void db1_ext(@Db("db1") GlobalConfig globalConfig) {
+        MetaObjectHandler metaObjectHandler = new MetaObjectHandlerImpl();
+
+        globalConfig.setMetaObjectHandler(metaObjectHandler);
+    }
+
+    @Bean
+    public void db1_ext2(@Db("db1") MybatisConfiguration config){
+        config.getTypeHandlerRegistry().register("xxx");
+        config.setDefaultEnumTypeHandler(null);
+    }
+
+    @Bean
+    public MybatisSqlSessionFactoryBuilder factoryBuilderNew(){
+        return new MybatisSqlSessionFactoryBuilderImpl();
+    }
+}

+ 22 - 0
mybatis-plus-solon-plugin/src/test/java/demo/DemoApp.java

@@ -0,0 +1,22 @@
+package demo;
+
+import com.baomidou.mybatisplus.core.toolkit.Assert;
+import demo.dso.service.UserService;
+import demo.model.User;
+import org.noear.solon.Solon;
+
+import java.util.List;
+
+/**
+ * @author noear 2021/7/12 created
+ */
+public class DemoApp {
+    public static void main(String[] args) {
+        Solon.start(DemoApp.class, args);
+
+        //test
+        UserService userService = Solon.context().getBean(UserService.class);
+
+        Assert.notNull(userService.getUserList(), "查询结果异常");
+    }
+}

+ 21 - 0
mybatis-plus-solon-plugin/src/test/java/demo/controller/IndexController.java

@@ -0,0 +1,21 @@
+package demo.controller;
+
+import demo.dso.service.UserService;
+import demo.model.User;
+import org.noear.solon.annotation.Controller;
+import org.noear.solon.annotation.Inject;
+import org.noear.solon.annotation.Mapping;
+
+import java.util.List;
+
+@Controller
+public class IndexController {
+
+    @Inject
+    UserService userService;
+
+    @Mapping("/")
+    public List<User> index() {
+        return userService.getUserList();
+    }
+}

+ 19 - 0
mybatis-plus-solon-plugin/src/test/java/demo/dso/MetaObjectHandlerImpl.java

@@ -0,0 +1,19 @@
+package demo.dso;
+
+import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
+import org.apache.ibatis.reflection.MetaObject;
+
+/**
+ * @author noear 2022/4/17 created
+ */
+public class MetaObjectHandlerImpl implements MetaObjectHandler {
+    @Override
+    public void insertFill(MetaObject metaObject) {
+
+    }
+
+    @Override
+    public void updateFill(MetaObject metaObject) {
+
+    }
+}

+ 9 - 0
mybatis-plus-solon-plugin/src/test/java/demo/dso/MybatisSqlSessionFactoryBuilderImpl.java

@@ -0,0 +1,9 @@
+package demo.dso;
+
+import com.baomidou.mybatisplus.core.MybatisSqlSessionFactoryBuilder;
+
+/**
+ * @author noear 2021/10/20 created
+ */
+public class MybatisSqlSessionFactoryBuilderImpl extends MybatisSqlSessionFactoryBuilder {
+}

+ 10 - 0
mybatis-plus-solon-plugin/src/test/java/demo/dso/mapper/UserMapper.java

@@ -0,0 +1,10 @@
+package demo.dso.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import demo.model.User;
+
+/**
+ * @author 颖
+ */
+public interface UserMapper extends BaseMapper<User> {
+}

+ 24 - 0
mybatis-plus-solon-plugin/src/test/java/demo/dso/service/UserService.java

@@ -0,0 +1,24 @@
+package demo.dso.service;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import demo.dso.mapper.UserMapper;
+import demo.model.User;
+import org.noear.solon.annotation.Component;
+import org.noear.solon.annotation.Inject;
+
+import java.util.List;
+
+/**
+ * @author noear 2021/9/9 created
+ */
+@Component
+public class UserService {
+    @Inject
+    UserMapper userMapper;
+
+    public List<User> getUserList() {
+        assert userMapper != null;
+
+        return userMapper.selectList(new QueryWrapper<>());
+    }
+}

+ 31 - 0
mybatis-plus-solon-plugin/src/test/java/demo/model/User.java

@@ -0,0 +1,31 @@
+package demo.model;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+
+/**
+ * @author iYarnFog
+ */
+@TableName(value = "users")
+public class User {
+    @TableId(type = IdType.AUTO)
+    private Long id;
+    private String uuid;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getUuid() {
+        return uuid;
+    }
+
+    public void setUuid(String uuid) {
+        this.uuid = uuid;
+    }
+}

+ 27 - 0
mybatis-plus-solon-plugin/src/test/java/features/IGenericTypeResolverImplTest.java

@@ -0,0 +1,27 @@
+package features;
+
+
+import com.baomidou.mybatisplus.core.mapper.Mapper;
+import demo.dso.mapper.UserMapper;
+import org.junit.jupiter.api.Test;
+import org.noear.solon.core.util.GenericUtil;
+
+import java.util.Arrays;
+import java.util.Map;
+
+public class IGenericTypeResolverImplTest {
+
+
+    @Test
+    public void resolveTypeArguments() {
+        System.out.println(Arrays.toString(GenericUtil.resolveTypeArguments(DemoImpl.class, Map.class)));
+        System.out.println(Arrays.toString(GenericUtil.resolveTypeArguments(DemoImpl.class, Demo.class)));
+
+        System.out.println(Arrays.toString(GenericUtil.resolveTypeArguments(UserMapper.class, Mapper.class)));
+    }
+
+    private interface Demo<T> {}
+    private abstract static class DemoImpl implements Map<Integer, String>, IGenericTypeResolverImplTest.Demo<Double> {
+
+    }
+}

+ 25 - 0
mybatis-plus-solon-plugin/src/test/resources/app.yml

@@ -0,0 +1,25 @@
+server:
+    port: 6040
+
+# 配置数据源
+dataSource:
+    db1:
+        # 与数据库名可用保持一致
+        schema: test
+        jdbcUrl: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&autoReconnect=true&rewriteBatchedStatements=true
+        driverClassName: com.mysql.cj.jdbc.Driver
+        username: root
+        password: 1234
+
+mybatis:
+    db1:
+        mappers:
+            - "demo.dso.mapper.*"
+        configuration:
+            cacheEnabled: false
+            mapUnderscoreToCamelCase: true
+        globalConfig:
+            banner: false
+            metaObjectHandler: "demo.dso.MetaObjectHandlerImpl"
+            dbConfig:
+                logicDeleteField: "deleted"

+ 29 - 0
mybatis-plus-spring/build.gradle

@@ -0,0 +1,29 @@
+apply plugin: 'kotlin'
+
+compileKotlin{
+    kotlinOptions.jvmTarget = "1.8"
+}
+
+dependencies {
+    api project(":mybatis-plus-extension")
+    implementation "${lib."mybatis-spring"}"
+
+    implementation "${lib."kotlin-stdlib-jdk8"}"
+    implementation "${lib."kotlin-reflect"}"
+    implementation "${lib."spring-context-support"}"
+    implementation "${lib."spring-jdbc"}"
+    implementation "${lib."slf4j-api"}"
+    implementation "${lib."p6spy"}"
+    implementation "${lib."jackson"}"
+    implementation "${lib."fastjson"}"
+    implementation "${lib."gson"}"
+    implementation "${lib['mybatis-thymeleaf']}"
+    implementation "${lib.'mybatis-velocity'}"
+    implementation "${lib.'mybatis-freemarker'}"
+    implementation "de.ruedigermoeller:fst:3.0.4-jdk17"
+    implementation "com.github.ben-manes.caffeine:caffeine:2.9.3"
+    testImplementation "io.github.classgraph:classgraph:4.8.176"
+    testImplementation "${lib.h2}"
+    testImplementation "${lib.mysql}"
+    testImplementation "${lib.'logback-classic'}"
+}

+ 39 - 0
mybatis-plus-spring/src/main/java/com/baomidou/mybatisplus/extension/activerecord/Model.java

@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2011-2024, 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.activerecord;
+
+import com.baomidou.mybatisplus.extension.toolkit.SqlRunner;
+
+/**
+ * ActiveRecord 模式 CRUD
+ * <p>
+ * 必须存在对应的原始mapper并继承baseMapper并且可以使用的前提下
+ * 才能使用此 AR 模式 !!!
+ * </p>
+ *
+ * @param <T>
+ * @author hubin
+ * @since 2016-11-06
+ */
+public abstract class Model<T extends Model<?>> extends AbstractModel<T> {
+
+    /**
+     * 执行 SQL
+     */
+    public SqlRunner sql() {
+        return new SqlRunner(this.entityClass);
+    }
+}

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

@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2011-2024, 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.compatible;
+
+import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
+import lombok.SneakyThrows;
+import org.apache.ibatis.exceptions.PersistenceException;
+import org.apache.ibatis.logging.Log;
+import org.apache.ibatis.reflection.ExceptionUtil;
+import org.apache.ibatis.session.ExecutorType;
+import org.apache.ibatis.session.SqlSession;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.mybatis.spring.MyBatisExceptionTranslator;
+import org.mybatis.spring.SqlSessionHolder;
+import org.mybatis.spring.SqlSessionUtils;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+
+import java.io.InputStream;
+import java.util.function.Consumer;
+
+/**
+ * spring 兼容方法集接口实现类
+ */
+public class SpringCompatibleSet implements CompatibleSet {
+
+    @Override
+    public SqlSession getSqlSession(SqlSessionFactory sessionFactory) {
+        return SqlSessionUtils.getSqlSession(sessionFactory);
+    }
+
+    @Override
+    public void closeSqlSession(SqlSession sqlSession, SqlSessionFactory sqlSessionFactory) {
+        SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
+    }
+
+    @SneakyThrows
+    @Override
+    public boolean executeBatch(SqlSessionFactory sqlSessionFactory, Log log, Consumer<SqlSession> consumer) {
+        SqlSessionHolder sqlSessionHolder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sqlSessionFactory);
+        boolean transaction = TransactionSynchronizationManager.isSynchronizationActive();
+        if (sqlSessionHolder != null) {
+            SqlSession sqlSession = sqlSessionHolder.getSqlSession();
+            //原生无法支持执行器切换,当存在批量操作时,会嵌套两个session的,优先commit上一个session
+            //按道理来说,这里的值应该一直为false。
+            sqlSession.commit(!transaction);
+        }
+        SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
+        if (!transaction) {
+            log.warn("SqlSession [" + sqlSession + "] Transaction not enabled");
+        }
+        try {
+            consumer.accept(sqlSession);
+            //非事务情况下,强制commit。
+            sqlSession.commit(!transaction);
+            return true;
+        } catch (Throwable t) {
+            sqlSession.rollback();
+            Throwable unwrapped = ExceptionUtil.unwrapThrowable(t);
+            if (unwrapped instanceof PersistenceException) {
+                MyBatisExceptionTranslator myBatisExceptionTranslator
+                    = new MyBatisExceptionTranslator(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(), true);
+                Throwable throwable = myBatisExceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
+                if (throwable != null) {
+                    throw throwable;
+                }
+            }
+            throw ExceptionUtils.mpe(unwrapped);
+        } finally {
+            sqlSession.close();
+        }
+    }
+
+    @Override
+    public InputStream getInputStream(String path) throws Exception {
+        return new ClassPathResource(path).getInputStream();
+    }
+}

+ 0 - 0
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/ddl/SimpleDdl.java → mybatis-plus-spring/src/main/java/com/baomidou/mybatisplus/extension/ddl/SimpleDdl.java


+ 103 - 0
mybatis-plus-spring/src/main/java/com/baomidou/mybatisplus/extension/repository/CrudRepository.java

@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2011-2024, 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.repository;
+
+import com.baomidou.mybatisplus.core.enums.SqlMethod;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.TableInfo;
+import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
+import com.baomidou.mybatisplus.core.toolkit.Assert;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
+import org.apache.ibatis.binding.MapperMethod;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Collection;
+
+/**
+ * IService 实现类( 泛型:M 是 mapper 对象,T 是实体 )
+ *
+ * @author hubin
+ * @since 2018-06-23
+ */
+public abstract class CrudRepository<M extends BaseMapper<T>, T> extends AbstractRepository<M, T> {
+
+    @Autowired
+    protected M baseMapper;
+
+    @Override
+    public M getBaseMapper() {
+        Assert.notNull(this.baseMapper, "baseMapper can not be null");
+        return this.baseMapper;
+    }
+
+    /**
+     * 批量插入
+     *
+     * @param entityList ignore
+     * @param batchSize  ignore
+     * @return ignore
+     */
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public boolean saveBatch(Collection<T> entityList, int batchSize) {
+        String sqlStatement = getSqlStatement(SqlMethod.INSERT_ONE);
+        return executeBatch(entityList, batchSize, (sqlSession, entity) -> sqlSession.insert(sqlStatement, entity));
+    }
+
+    /**
+     * 获取mapperStatementId
+     *
+     * @param sqlMethod 方法名
+     * @return 命名id
+     * @since 3.4.0
+     */
+    protected String getSqlStatement(SqlMethod sqlMethod) {
+        return SqlHelper.getSqlStatement(this.getMapperClass(), sqlMethod);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize) {
+        TableInfo tableInfo = TableInfoHelper.getTableInfo(this.getEntityClass());
+        Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!");
+        String keyProperty = tableInfo.getKeyProperty();
+        Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!");
+        return SqlHelper.saveOrUpdateBatch(getSqlSessionFactory(), this.getMapperClass(), this.log, entityList, batchSize, (sqlSession, entity) -> {
+            Object idVal = tableInfo.getPropertyValue(entity, keyProperty);
+            return StringUtils.checkValNull(idVal)
+                || CollectionUtils.isEmpty(sqlSession.selectList(getSqlStatement(SqlMethod.SELECT_BY_ID), entity));
+        }, (sqlSession, entity) -> {
+            MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
+            param.put(Constants.ENTITY, entity);
+            sqlSession.update(getSqlStatement(SqlMethod.UPDATE_BY_ID), param);
+        });
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public boolean updateBatchById(Collection<T> entityList, int batchSize) {
+        String sqlStatement = getSqlStatement(SqlMethod.UPDATE_BY_ID);
+        return executeBatch(entityList, batchSize, (sqlSession, entity) -> {
+            MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
+            param.put(Constants.ENTITY, entity);
+            sqlSession.update(sqlStatement, param);
+        });
+    }
+}

+ 75 - 0
mybatis-plus-spring/src/main/java/com/baomidou/mybatisplus/extension/service/IService.java

@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2011-2024, 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.service;
+
+import com.baomidou.mybatisplus.extension.repository.IRepository;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Collection;
+
+/**
+ * 顶级 Service
+ * <p>
+ *
+ * </p>
+ *
+ * @author hubin
+ * @since 2018-06-23
+ */
+public interface IService<T> extends IRepository<T> {
+
+    /**
+     * 插入(批量)
+     *
+     * @param entityList 实体对象集合
+     */
+    @Transactional(rollbackFor = Exception.class)
+    default boolean saveBatch(Collection<T> entityList) {
+        return saveBatch(entityList, DEFAULT_BATCH_SIZE);
+    }
+
+    /**
+     * 批量修改插入
+     *
+     * @param entityList 实体对象集合
+     */
+    @Transactional(rollbackFor = Exception.class)
+    default boolean saveOrUpdateBatch(Collection<T> entityList) {
+        return saveOrUpdateBatch(entityList, DEFAULT_BATCH_SIZE);
+    }
+
+    /**
+     * 批量删除(jdbc批量提交)
+     *
+     * @param list 主键ID或实体列表(主键ID类型必须与实体类型字段保持一致)
+     * @return 删除结果
+     * @since 3.5.0
+     */
+    @Transactional(rollbackFor = Exception.class)
+    default boolean removeBatchByIds(Collection<?> list) {
+        return removeByIds(list);
+    }
+
+    /**
+     * 根据ID 批量更新
+     *
+     * @param entityList 实体对象集合
+     */
+    @Transactional(rollbackFor = Exception.class)
+    default boolean updateBatchById(Collection<T> entityList) {
+        return updateBatchById(entityList, DEFAULT_BATCH_SIZE);
+    }
+}

+ 30 - 0
mybatis-plus-spring/src/main/java/com/baomidou/mybatisplus/extension/service/impl/ServiceImpl.java

@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2011-2024, 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.service.impl;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.repository.CrudRepository;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * IService 实现类( 泛型:M 是 mapper 对象,T 是实体 )
+ *
+ * @author hubin
+ * @since 2018-06-23
+ */
+public class ServiceImpl<M extends BaseMapper<T>, T> extends CrudRepository<M, T> implements IService<T> {
+
+}

+ 22 - 0
mybatis-plus-spring/src/main/java/com/baomidou/mybatisplus/extension/service/impl/package-info.java

@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2011-2024, 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.
+ */
+/**
+ * 通用 service 实现
+ *
+ * @author hubin
+ * @since 2018-06-08
+ */
+package com.baomidou.mybatisplus.extension.service.impl;

+ 5 - 2
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/spring/package-info.java → mybatis-plus-spring/src/main/java/com/baomidou/mybatisplus/extension/service/package-info.java

@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 /**
- * Spring相关类
+ * 通用 Service 接口
+ *
+ * @author hubin
+ * @since 2018-06-08
  */
-package com.baomidou.mybatisplus.extension.spring;
+package com.baomidou.mybatisplus.extension.service;

+ 2 - 12
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/spring/MybatisSqlSessionFactoryBean.java → mybatis-plus-spring/src/main/java/com/baomidou/mybatisplus/extension/spring/MybatisSqlSessionFactoryBean.java

@@ -15,11 +15,7 @@
  */
 package com.baomidou.mybatisplus.extension.spring;
 
-import com.baomidou.mybatisplus.core.MybatisConfiguration;
-import com.baomidou.mybatisplus.core.MybatisPlusVersion;
-import com.baomidou.mybatisplus.core.MybatisSqlSessionFactoryBuilder;
-import com.baomidou.mybatisplus.core.MybatisXMLConfigBuilder;
-import com.baomidou.mybatisplus.core.MybatisXMLMapperBuilder;
+import com.baomidou.mybatisplus.core.*;
 import com.baomidou.mybatisplus.core.config.GlobalConfig;
 import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils;
 import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
@@ -61,13 +57,7 @@ import javax.sql.DataSource;
 import java.io.IOException;
 import java.lang.reflect.Modifier;
 import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Optional;
-import java.util.Properties;
-import java.util.Set;
+import java.util.*;
 import java.util.function.IntFunction;
 import java.util.stream.Stream;
 

+ 0 - 0
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/toolkit/SqlRunner.java → mybatis-plus-spring/src/main/java/com/baomidou/mybatisplus/extension/toolkit/SqlRunner.java


+ 0 - 1
mybatis-plus-extension/src/test/java/com/baomidou/mybatisplus/test/service/ServiceTest.java → mybatis-plus-spring/src/test/java/com/baomidou/mybatisplus/test/service/ServiceTest.java

@@ -10,7 +10,6 @@ import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 import org.mockito.Mockito;
 
-
 import static org.assertj.core.api.Assertions.assertThat;
 
 /**

+ 1 - 0
mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/logicdel/EntityMapper.java

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.toolkit.Constants;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
+
 import java.util.List;
 
 

+ 0 - 1
mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/phoenix/PhoenixTest.java

@@ -16,7 +16,6 @@ import org.springframework.test.annotation.DirtiesContext;
 import org.springframework.test.context.ContextConfiguration;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
 
-
 import static com.baomidou.mybatisplus.core.enums.SqlMethod.UPSERT_ONE;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 

+ 0 - 2
mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/sqlrunner/SqlRunnerTest.java

@@ -13,8 +13,6 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
-import static org.assertj.core.api.Assertions.assertThat;
-
 /**
  * @author miemie
  * @since 2021-03-16

+ 4 - 5
mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/toolkit/SqlHelperTest.java

@@ -1,16 +1,15 @@
 package com.baomidou.mybatisplus.test.toolkit;
 
-import java.util.Arrays;
-import java.util.List;
-
-import org.junit.jupiter.api.Test;
-
 import com.baomidou.mybatisplus.core.toolkit.Assert;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
 import com.baomidou.mybatisplus.test.BaseDbTest;
 import com.baomidou.mybatisplus.test.rewrite.Entity;
 import com.baomidou.mybatisplus.test.rewrite.EntityMapper;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.List;
 
 /**
  * SqlHelper 工具类测试

+ 2 - 0
settings.gradle

@@ -21,6 +21,8 @@ include 'mybatis-plus-annotation'
 include 'mybatis-plus-extension'
 include 'mybatis-plus-generator'
 include 'mybatis-plus-bom'
+include 'mybatis-plus-spring'
+include 'mybatis-plus-solon-plugin'
 include 'spring-boot-starter'
 include ':spring-boot-starter:mybatis-plus-boot-starter'
 include ':spring-boot-starter:mybatis-plus-boot-starter-test'

+ 2 - 0
spring-boot-starter/mybatis-plus-spring-boot-autoconfigure/build.gradle

@@ -1,4 +1,6 @@
 dependencies {
+    api project(":mybatis-plus-spring")
+
     implementation project(":mybatis-plus")
     implementation "${lib."mybatis-spring"}"
     implementation "org.springframework.boot:spring-boot-autoconfigure:${springBootVersion}"

+ 5 - 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.extension.compatible.CompatibleHelper;
+import com.baomidou.mybatisplus.extension.compatible.SpringCompatibleSet;
 import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.mapping.DatabaseIdProvider;
@@ -148,6 +150,9 @@ public class MybatisPlusAutoConfiguration implements InitializingBean {
         this.sqlSessionFactoryBeanCustomizers = sqlSessionFactoryBeanCustomizers.getIfAvailable();
         this.mybatisPlusPropertiesCustomizers = mybatisPlusPropertiesCustomizerProvider.getIfAvailable();
         this.applicationContext = applicationContext;
+
+        // 注入兼容配置
+        CompatibleHelper.setCompatibleSet(new SpringCompatibleSet());
     }
 
     @Override