Browse Source

!223 【新特性】新增Db类,不用每张表都新建Service及其实现类了
Merge pull request !223 from 阿超/3.0

青苗 2 years ago
parent
commit
eca0d60359
13 changed files with 1009 additions and 13 deletions
  1. 22 0
      mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/conditions/ChainWrapper.java
  2. 7 7
      mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/conditions/query/ChainQuery.java
  3. 16 2
      mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/conditions/query/LambdaQueryChainWrapper.java
  4. 21 2
      mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/conditions/query/QueryChainWrapper.java
  5. 2 2
      mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/conditions/update/ChainUpdate.java
  6. 14 0
      mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/conditions/update/LambdaUpdateChainWrapper.java
  7. 14 0
      mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/conditions/update/UpdateChainWrapper.java
  8. 16 0
      mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/toolkit/ChainWrappers.java
  9. 568 0
      mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/toolkit/Db.java
  10. 4 0
      mybatis-plus-extension/src/main/kotlin/com/baomidou/mybatisplus/extension/kotlin/KtQueryChainWrapper.kt
  11. 4 0
      mybatis-plus-extension/src/main/kotlin/com/baomidou/mybatisplus/extension/kotlin/KtUpdateChainWrapper.kt
  12. 46 0
      mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/chainwrapper/ChainWrappersTest.java
  13. 275 0
      mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/toolkit/DbTest.java

+ 22 - 0
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/conditions/ChainWrapper.java

@@ -15,8 +15,12 @@
  */
  */
 package com.baomidou.mybatisplus.extension.conditions;
 package com.baomidou.mybatisplus.extension.conditions;
 
 
+import java.util.Optional;
+
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
+import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
 
 
 /**
 /**
  * 此接口没特殊意义,只是为了减少实现类的代码量,主要在 AbstractChainWrapper 抽象类上实现
  * 此接口没特殊意义,只是为了减少实现类的代码量,主要在 AbstractChainWrapper 抽象类上实现
@@ -40,4 +44,22 @@ public interface ChainWrapper<T> {
      * @return Wrapper
      * @return Wrapper
      */
      */
     Wrapper<T> getWrapper();
     Wrapper<T> getWrapper();
+
+    /**
+     * 获取当前实体Class
+     *
+     * @return Class
+     */
+    Class<T> getEntityClass();
+
+    /**
+     * 执行baseMapper操作,有baseMapper操作时使用baseMapper,没有时通过entityClass获取baseMapper,再使用
+     *
+     * @param function 操作
+     * @param <R>      返回值
+     * @return 结果
+     */
+    default <R> R execute(SFunction<BaseMapper<T>, R> function) {
+        return Optional.ofNullable(getBaseMapper()).map(function).orElseGet(() -> SqlHelper.execute(getEntityClass(), function));
+    }
 }
 }

+ 7 - 7
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/conditions/query/ChainQuery.java

@@ -15,13 +15,13 @@
  */
  */
 package com.baomidou.mybatisplus.extension.conditions.query;
 package com.baomidou.mybatisplus.extension.conditions.query;
 
 
+import java.util.List;
+import java.util.Optional;
+
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.conditions.ChainWrapper;
 import com.baomidou.mybatisplus.extension.conditions.ChainWrapper;
 import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
 import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
 
 
-import java.util.List;
-import java.util.Optional;
-
 /**
 /**
  * 具有查询方法的定义
  * 具有查询方法的定义
  *
  *
@@ -36,7 +36,7 @@ public interface ChainQuery<T> extends ChainWrapper<T> {
      * @return 集合
      * @return 集合
      */
      */
     default List<T> list() {
     default List<T> list() {
-        return getBaseMapper().selectList(getWrapper());
+        return execute(mapper -> mapper.selectList(getWrapper()));
     }
     }
 
 
     /**
     /**
@@ -45,7 +45,7 @@ public interface ChainQuery<T> extends ChainWrapper<T> {
      * @return 单个
      * @return 单个
      */
      */
     default T one() {
     default T one() {
-        return getBaseMapper().selectOne(getWrapper());
+        return execute(mapper -> mapper.selectOne(getWrapper()));
     }
     }
 
 
     /**
     /**
@@ -64,7 +64,7 @@ public interface ChainQuery<T> extends ChainWrapper<T> {
      * @return count
      * @return count
      */
      */
     default Long count() {
     default Long count() {
-        return SqlHelper.retCount(getBaseMapper().selectCount(getWrapper()));
+        return execute(mapper -> SqlHelper.retCount(mapper.selectCount(getWrapper())));
     }
     }
 
 
     /**
     /**
@@ -83,6 +83,6 @@ public interface ChainQuery<T> extends ChainWrapper<T> {
      * @return 分页数据
      * @return 分页数据
      */
      */
     default <E extends IPage<T>> E page(E page) {
     default <E extends IPage<T>> E page(E page) {
-        return getBaseMapper().selectPage(page, getWrapper());
+        return execute(mapper -> mapper.selectPage(page, getWrapper()));
     }
     }
 }
 }

+ 16 - 2
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/conditions/query/LambdaQueryChainWrapper.java

@@ -15,6 +15,8 @@
  */
  */
 package com.baomidou.mybatisplus.extension.conditions.query;
 package com.baomidou.mybatisplus.extension.conditions.query;
 
 
+import java.util.function.Predicate;
+
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.Query;
 import com.baomidou.mybatisplus.core.conditions.query.Query;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
@@ -23,8 +25,6 @@ import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
 import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
 import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
 import com.baomidou.mybatisplus.extension.conditions.AbstractChainWrapper;
 import com.baomidou.mybatisplus.extension.conditions.AbstractChainWrapper;
 
 
-import java.util.function.Predicate;
-
 /**
 /**
  * @author miemie
  * @author miemie
  * @since 2018-12-19
  * @since 2018-12-19
@@ -34,10 +34,19 @@ public class LambdaQueryChainWrapper<T> extends AbstractChainWrapper<T, SFunctio
     implements ChainQuery<T>, Query<LambdaQueryChainWrapper<T>, T, SFunction<T, ?>> {
     implements ChainQuery<T>, Query<LambdaQueryChainWrapper<T>, T, SFunction<T, ?>> {
 
 
     private final BaseMapper<T> baseMapper;
     private final BaseMapper<T> baseMapper;
+    private final Class<T> entityClass;
 
 
     public LambdaQueryChainWrapper(BaseMapper<T> baseMapper) {
     public LambdaQueryChainWrapper(BaseMapper<T> baseMapper) {
         super();
         super();
         this.baseMapper = baseMapper;
         this.baseMapper = baseMapper;
+        this.entityClass = null;
+        super.wrapperChildren = new LambdaQueryWrapper<>();
+    }
+
+    public LambdaQueryChainWrapper(Class<T> entityClass) {
+        super();
+        this.baseMapper = null;
+        this.entityClass = entityClass;
         super.wrapperChildren = new LambdaQueryWrapper<>();
         super.wrapperChildren = new LambdaQueryWrapper<>();
     }
     }
 
 
@@ -75,4 +84,9 @@ public class LambdaQueryChainWrapper<T> extends AbstractChainWrapper<T, SFunctio
     public BaseMapper<T> getBaseMapper() {
     public BaseMapper<T> getBaseMapper() {
         return baseMapper;
         return baseMapper;
     }
     }
+
+    @Override
+    public Class<T> getEntityClass() {
+        return entityClass;
+    }
 }
 }

+ 21 - 2
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/conditions/query/QueryChainWrapper.java

@@ -15,6 +15,8 @@
  */
  */
 package com.baomidou.mybatisplus.extension.conditions.query;
 package com.baomidou.mybatisplus.extension.conditions.query;
 
 
+import java.util.function.Predicate;
+
 import com.baomidou.mybatisplus.core.conditions.query.Query;
 import com.baomidou.mybatisplus.core.conditions.query.Query;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
@@ -22,8 +24,6 @@ import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
 import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
 import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
 import com.baomidou.mybatisplus.extension.conditions.AbstractChainWrapper;
 import com.baomidou.mybatisplus.extension.conditions.AbstractChainWrapper;
 
 
-import java.util.function.Predicate;
-
 /**
 /**
  * Query Chain Wrapper
  * Query Chain Wrapper
  *
  *
@@ -35,10 +35,19 @@ public class QueryChainWrapper<T> extends AbstractChainWrapper<T, String, QueryC
     implements ChainQuery<T>, Query<QueryChainWrapper<T>, T, String> {
     implements ChainQuery<T>, Query<QueryChainWrapper<T>, T, String> {
 
 
     private final BaseMapper<T> baseMapper;
     private final BaseMapper<T> baseMapper;
+    private final Class<T> entityClass;
 
 
     public QueryChainWrapper(BaseMapper<T> baseMapper) {
     public QueryChainWrapper(BaseMapper<T> baseMapper) {
         super();
         super();
         this.baseMapper = baseMapper;
         this.baseMapper = baseMapper;
+        this.entityClass = null;
+        super.wrapperChildren = new QueryWrapper<>();
+    }
+
+    public QueryChainWrapper(Class<T> entityClass) {
+        super();
+        this.baseMapper = null;
+        this.entityClass = entityClass;
         super.wrapperChildren = new QueryWrapper<>();
         super.wrapperChildren = new QueryWrapper<>();
     }
     }
 
 
@@ -63,4 +72,14 @@ public class QueryChainWrapper<T> extends AbstractChainWrapper<T, String, QueryC
     public BaseMapper<T> getBaseMapper() {
     public BaseMapper<T> getBaseMapper() {
         return baseMapper;
         return baseMapper;
     }
     }
+
+    /**
+     * 获取当前实体Class
+     *
+     * @return Class
+     */
+    @Override
+    public Class<T> getEntityClass() {
+        return entityClass;
+    }
 }
 }

+ 2 - 2
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/conditions/update/ChainUpdate.java

@@ -42,7 +42,7 @@ public interface ChainUpdate<T> extends ChainWrapper<T> {
      * @return 是否成功
      * @return 是否成功
      */
      */
     default boolean update(T entity) {
     default boolean update(T entity) {
-        return SqlHelper.retBool(getBaseMapper().update(entity, getWrapper()));
+        return execute(mapper -> SqlHelper.retBool(mapper.update(entity, getWrapper())));
     }
     }
 
 
     /**
     /**
@@ -51,6 +51,6 @@ public interface ChainUpdate<T> extends ChainWrapper<T> {
      * @return 是否成功
      * @return 是否成功
      */
      */
     default boolean remove() {
     default boolean remove() {
-        return SqlHelper.retBool(getBaseMapper().delete(getWrapper()));
+        return execute(mapper -> SqlHelper.retBool(mapper.delete(getWrapper())));
     }
     }
 }
 }

+ 14 - 0
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/conditions/update/LambdaUpdateChainWrapper.java

@@ -33,10 +33,19 @@ public class LambdaUpdateChainWrapper<T> extends AbstractChainWrapper<T, SFuncti
     implements ChainUpdate<T>, Update<LambdaUpdateChainWrapper<T>, SFunction<T, ?>> {
     implements ChainUpdate<T>, Update<LambdaUpdateChainWrapper<T>, SFunction<T, ?>> {
 
 
     private final BaseMapper<T> baseMapper;
     private final BaseMapper<T> baseMapper;
+    private final Class<T> entityClass;
 
 
     public LambdaUpdateChainWrapper(BaseMapper<T> baseMapper) {
     public LambdaUpdateChainWrapper(BaseMapper<T> baseMapper) {
         super();
         super();
         this.baseMapper = baseMapper;
         this.baseMapper = baseMapper;
+        this.entityClass = null;
+        super.wrapperChildren = new LambdaUpdateWrapper<>();
+    }
+
+    public LambdaUpdateChainWrapper(Class<T> entityClass) {
+        super();
+        this.baseMapper = null;
+        this.entityClass = entityClass;
         super.wrapperChildren = new LambdaUpdateWrapper<>();
         super.wrapperChildren = new LambdaUpdateWrapper<>();
     }
     }
 
 
@@ -61,4 +70,9 @@ public class LambdaUpdateChainWrapper<T> extends AbstractChainWrapper<T, SFuncti
     public BaseMapper<T> getBaseMapper() {
     public BaseMapper<T> getBaseMapper() {
         return baseMapper;
         return baseMapper;
     }
     }
+
+    @Override
+    public Class<T> getEntityClass() {
+        return entityClass;
+    }
 }
 }

+ 14 - 0
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/conditions/update/UpdateChainWrapper.java

@@ -32,10 +32,19 @@ public class UpdateChainWrapper<T> extends AbstractChainWrapper<T, String, Updat
     implements ChainUpdate<T>, Update<UpdateChainWrapper<T>, String> {
     implements ChainUpdate<T>, Update<UpdateChainWrapper<T>, String> {
 
 
     private final BaseMapper<T> baseMapper;
     private final BaseMapper<T> baseMapper;
+    private final Class<T> entityClass;
 
 
     public UpdateChainWrapper(BaseMapper<T> baseMapper) {
     public UpdateChainWrapper(BaseMapper<T> baseMapper) {
         super();
         super();
         this.baseMapper = baseMapper;
         this.baseMapper = baseMapper;
+        this.entityClass = null;
+        super.wrapperChildren = new UpdateWrapper<>();
+    }
+
+    public UpdateChainWrapper(Class<T> entityClass) {
+        super();
+        this.baseMapper = null;
+        this.entityClass = entityClass;
         super.wrapperChildren = new UpdateWrapper<>();
         super.wrapperChildren = new UpdateWrapper<>();
     }
     }
 
 
@@ -60,4 +69,9 @@ public class UpdateChainWrapper<T> extends AbstractChainWrapper<T, String, Updat
     public BaseMapper<T> getBaseMapper() {
     public BaseMapper<T> getBaseMapper() {
         return baseMapper;
         return baseMapper;
     }
     }
+
+    @Override
+    public Class<T> getEntityClass() {
+        return entityClass;
+    }
 }
 }

+ 16 - 0
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/toolkit/ChainWrappers.java

@@ -45,6 +45,10 @@ public final class ChainWrappers {
         return new QueryChainWrapper<>(mapper);
         return new QueryChainWrapper<>(mapper);
     }
     }
 
 
+    public static <T> QueryChainWrapper<T> queryChain(Class<T> entityClass) {
+        return new QueryChainWrapper<>(entityClass);
+    }
+
     /**
     /**
      * 链式查询 lambda 式
      * 链式查询 lambda 式
      * <p>注意:不支持 Kotlin </p>
      * <p>注意:不支持 Kotlin </p>
@@ -55,6 +59,10 @@ public final class ChainWrappers {
         return new LambdaQueryChainWrapper<>(mapper);
         return new LambdaQueryChainWrapper<>(mapper);
     }
     }
 
 
+    public static <T> LambdaQueryChainWrapper<T> lambdaQueryChain(Class<T> entityClass) {
+        return new LambdaQueryChainWrapper<>(entityClass);
+    }
+
     /**
     /**
      * 链式查询 lambda 式
      * 链式查询 lambda 式
      * <p>注意:不支持 Kotlin </p>
      * <p>注意:不支持 Kotlin </p>
@@ -104,6 +112,10 @@ public final class ChainWrappers {
         return new UpdateChainWrapper<>(mapper);
         return new UpdateChainWrapper<>(mapper);
     }
     }
 
 
+    public static <T> UpdateChainWrapper<T> updateChain(Class<T> entityClass) {
+        return new UpdateChainWrapper<>(entityClass);
+    }
+
     /**
     /**
      * 链式更改 lambda 式
      * 链式更改 lambda 式
      * <p>注意:不支持 Kotlin </p>
      * <p>注意:不支持 Kotlin </p>
@@ -114,6 +126,10 @@ public final class ChainWrappers {
         return new LambdaUpdateChainWrapper<>(mapper);
         return new LambdaUpdateChainWrapper<>(mapper);
     }
     }
 
 
+    public static <T> LambdaUpdateChainWrapper<T> lambdaUpdateChain(Class<T> entityClass) {
+        return new LambdaUpdateChainWrapper<>(entityClass);
+    }
+
     /**
     /**
      * 链式更改 lambda 式
      * 链式更改 lambda 式
      * 仅支持 Kotlin
      * 仅支持 Kotlin

+ 568 - 0
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/toolkit/Db.java

@@ -0,0 +1,568 @@
+package com.baomidou.mybatisplus.extension.toolkit;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.apache.ibatis.binding.MapperMethod;
+import org.apache.ibatis.logging.Log;
+import org.apache.ibatis.logging.LogFactory;
+
+import com.baomidou.mybatisplus.core.conditions.AbstractWrapper;
+import com.baomidou.mybatisplus.core.enums.SqlMethod;
+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.Assert;
+import com.baomidou.mybatisplus.core.toolkit.ClassUtils;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
+import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
+import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper;
+import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
+import com.baomidou.mybatisplus.extension.conditions.update.UpdateChainWrapper;
+
+/**
+ * 以静态方式调用Service中的函数
+ *
+ * @author VampireAchao
+ * @since 2022-05-03
+ */
+public class Db {
+
+    /**
+     * 默认批次提交数量
+     */
+    public static final int DEFAULT_BATCH_SIZE = 1000;
+    private static final Log log = LogFactory.getLog(Db.class);
+
+    private Db() {
+        /* Do not new me! */
+    }
+
+    /**
+     * 插入一条记录(选择字段,策略插入)
+     *
+     * @param entity 实体对象
+     */
+    public static <T> boolean save(T entity) {
+        if (Objects.isNull(entity)) {
+            return false;
+        }
+        @SuppressWarnings("unchecked")
+        Class<T> entityClass = (Class<T>) entity.getClass();
+        Integer result = SqlHelper.execute(entityClass, baseMapper -> baseMapper.insert(entity));
+        return SqlHelper.retBool(result);
+    }
+
+    /**
+     * 插入(批量)
+     *
+     * @param entityList 实体对象集合
+     */
+    public static <T> boolean saveBatch(Collection<T> entityList) {
+        return saveBatch(entityList, DEFAULT_BATCH_SIZE);
+    }
+
+    /**
+     * 插入(批量)
+     *
+     * @param entityList 实体对象集合
+     * @param batchSize  插入批次数量
+     */
+    public static <T> boolean saveBatch(Collection<T> entityList, int batchSize) {
+        if (CollectionUtils.isEmpty(entityList)) {
+            return false;
+        }
+        Class<T> entityClass = getEntityClass(entityList);
+        Class<?> mapperClass = ClassUtils.toClassConfident(getTableInfo(entityClass).getCurrentNamespace());
+        String sqlStatement = SqlHelper.getSqlStatement(mapperClass, SqlMethod.INSERT_ONE);
+        return SqlHelper.executeBatch(entityClass, LogFactory.getLog(Db.class), entityList, batchSize, (sqlSession, entity) -> sqlSession.insert(sqlStatement, entity));
+    }
+
+    /**
+     * 批量修改插入
+     *
+     * @param entityList 实体对象集合
+     */
+    public static <T> boolean saveOrUpdateBatch(Collection<T> entityList) {
+        return saveOrUpdateBatch(entityList, DEFAULT_BATCH_SIZE);
+    }
+
+    /**
+     * 批量修改插入
+     *
+     * @param entityList 实体对象集合
+     * @param batchSize  每次的数量
+     */
+    public static <T> boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize) {
+        if (CollectionUtils.isEmpty(entityList)) {
+            return false;
+        }
+        Class<T> entityClass = getEntityClass(entityList);
+        TableInfo tableInfo = getTableInfo(entityClass);
+        Class<?> mapperClass = ClassUtils.toClassConfident(tableInfo.getCurrentNamespace());
+        String keyProperty = tableInfo.getKeyProperty();
+        Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for primary key from entity!");
+        return SqlHelper.saveOrUpdateBatch(entityClass, mapperClass, LogFactory.getLog(Db.class), entityList, batchSize, (sqlSession, entity) -> {
+            Object idVal = tableInfo.getPropertyValue(entity, keyProperty);
+            return StringUtils.checkValNull(idVal)
+                || CollectionUtils.isEmpty(sqlSession.selectList(SqlHelper.getSqlStatement(mapperClass, SqlMethod.SELECT_BY_ID), entity));
+        }, (sqlSession, entity) -> {
+            MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
+            param.put(Constants.ENTITY, entity);
+            sqlSession.update(SqlHelper.getSqlStatement(mapperClass, SqlMethod.UPDATE_BY_ID), param);
+        });
+    }
+
+    /**
+     * 根据 ID 删除
+     *
+     * @param id          主键ID
+     * @param entityClass 实体类
+     */
+    public static <T> boolean removeById(Serializable id, Class<T> entityClass) {
+        return SqlHelper.execute(entityClass, baseMapper -> SqlHelper.retBool(baseMapper.deleteById(id)));
+    }
+
+    /**
+     * 根据实体(ID)删除
+     *
+     * @param entity 实体
+     */
+    public static <T> boolean removeById(T entity) {
+        if (Objects.isNull(entity)) {
+            return false;
+        }
+        @SuppressWarnings("unchecked")
+        Class<T> entityClass = (Class<T>) entity.getClass();
+        return SqlHelper.execute(entityClass, baseMapper -> SqlHelper.retBool(baseMapper.deleteById(entity)));
+    }
+
+    /**
+     * 根据 entity 条件,删除记录
+     *
+     * @param queryWrapper 实体包装类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
+     */
+    public static <T> boolean remove(AbstractWrapper<T, ?, ?> queryWrapper) {
+        return SqlHelper.execute(getEntityClass(queryWrapper), baseMapper -> SqlHelper.retBool(baseMapper.delete(queryWrapper)));
+    }
+
+    /**
+     * 根据 ID 选择修改
+     *
+     * @param entity 实体对象
+     */
+    public static <T> boolean updateById(T entity) {
+        if (Objects.isNull(entity)) {
+            return false;
+        }
+        @SuppressWarnings("unchecked")
+        Class<T> entityClass = (Class<T>) entity.getClass();
+        return SqlHelper.execute(entityClass, baseMapper -> SqlHelper.retBool(baseMapper.updateById(entity)));
+    }
+
+    /**
+     * 根据 UpdateWrapper 条件,更新记录 需要设置sqlset
+     *
+     * @param updateWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper}
+     */
+    public static <T> boolean update(AbstractWrapper<T, ?, ?> updateWrapper) {
+        return update(null, updateWrapper);
+    }
+
+    /**
+     * 根据 whereEntity 条件,更新记录
+     *
+     * @param entity        实体对象
+     * @param updateWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper}
+     */
+    public static <T> boolean update(T entity, AbstractWrapper<T, ?, ?> updateWrapper) {
+        return SqlHelper.execute(getEntityClass(updateWrapper), baseMapper -> SqlHelper.retBool(baseMapper.update(entity, updateWrapper)));
+    }
+
+    /**
+     * 根据ID 批量更新
+     *
+     * @param entityList 实体对象集合
+     */
+    public static <T> boolean updateBatchById(Collection<T> entityList) {
+        return updateBatchById(entityList, DEFAULT_BATCH_SIZE);
+    }
+
+    /**
+     * 根据ID 批量更新
+     *
+     * @param entityList 实体对象集合
+     * @param batchSize  更新批次数量
+     */
+    public static <T> boolean updateBatchById(Collection<T> entityList, int batchSize) {
+        Class<T> entityClass = getEntityClass(entityList);
+        TableInfo tableInfo = getTableInfo(entityClass);
+        String sqlStatement = SqlHelper.getSqlStatement(ClassUtils.toClassConfident(tableInfo.getCurrentNamespace()), SqlMethod.UPDATE_BY_ID);
+        return SqlHelper.executeBatch(entityClass, LogFactory.getLog(Db.class), entityList, batchSize, (sqlSession, entity) -> {
+            MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
+            param.put(Constants.ENTITY, entity);
+            sqlSession.update(sqlStatement, param);
+        });
+    }
+
+    /**
+     * 删除(根据ID 批量删除)
+     *
+     * @param list        主键ID或实体列表
+     * @param entityClass 实体类
+     */
+    public static <T> boolean removeByIds(Collection<? extends Serializable> list, Class<T> entityClass) {
+        return SqlHelper.execute(entityClass, baseMapper -> SqlHelper.retBool(baseMapper.deleteBatchIds(list)));
+    }
+
+    /**
+     * 根据 columnMap 条件,删除记录
+     *
+     * @param columnMap   表字段 map 对象
+     * @param entityClass 实体类
+     */
+    public static <T> boolean removeByMap(Map<String, Object> columnMap, Class<T> entityClass) {
+        return SqlHelper.execute(entityClass, baseMapper -> SqlHelper.retBool(baseMapper.deleteByMap(columnMap)));
+    }
+
+    /**
+     * TableId 注解存在更新记录,否插入一条记录
+     *
+     * @param entity 实体对象
+     */
+    public static <T> boolean saveOrUpdate(T entity) {
+        if (Objects.isNull(entity)) {
+            return false;
+        }
+        @SuppressWarnings("unchecked")
+        Class<T> entityClass = (Class<T>) entity.getClass();
+        TableInfo tableInfo = TableInfoHelper.getTableInfo(entityClass);
+        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!");
+        Object idVal = tableInfo.getPropertyValue(entity, tableInfo.getKeyProperty());
+        return StringUtils.checkValNull(idVal) || Objects.isNull(getById((Serializable) idVal, entityClass)) ? save(entity) : updateById(entity);
+    }
+
+    /**
+     * 根据 ID 查询
+     *
+     * @param id          主键ID
+     * @param entityClass 实体类
+     */
+    public static <T> T getById(Serializable id, Class<T> entityClass) {
+        return SqlHelper.execute(entityClass, baseMapper -> baseMapper.selectById(id));
+    }
+
+    /**
+     * 根据 Wrapper,查询一条记录 <br/>
+     * <p>结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")</p>
+     *
+     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
+     */
+    public static <T> T getOne(AbstractWrapper<T, ?, ?> queryWrapper) {
+        return getOne(queryWrapper, true);
+    }
+
+    /**
+     * 根据 Wrapper,查询一条记录
+     *
+     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
+     * @param throwEx      有多个 result 是否抛出异常
+     */
+    public static <T> T getOne(AbstractWrapper<T, ?, ?> queryWrapper, boolean throwEx) {
+        Class<T> entityClass = getEntityClass(queryWrapper);
+        if (throwEx) {
+            return SqlHelper.execute(entityClass, baseMapper -> baseMapper.selectOne(queryWrapper));
+        }
+        return SqlHelper.execute(entityClass, baseMapper -> SqlHelper.getObject(log, baseMapper.selectList(queryWrapper)));
+    }
+
+    /**
+     * 查询(根据 columnMap 条件)
+     *
+     * @param columnMap   表字段 map 对象
+     * @param entityClass 实体类
+     */
+    public static <T> List<T> listByMap(Map<String, Object> columnMap, Class<T> entityClass) {
+        return SqlHelper.execute(entityClass, baseMapper -> baseMapper.selectByMap(columnMap));
+    }
+
+    /**
+     * 查询(根据ID 批量查询)
+     *
+     * @param idList      主键ID列表
+     * @param entityClass 实体类
+     */
+    public static <T> List<T> listByIds(Collection<? extends Serializable> idList, Class<T> entityClass) {
+        return SqlHelper.execute(entityClass, baseMapper -> baseMapper.selectBatchIds(idList));
+    }
+
+    /**
+     * 根据 Wrapper,查询一条记录
+     *
+     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
+     */
+    public static <T> Map<String, Object> getMap(AbstractWrapper<T, ?, ?> queryWrapper) {
+        return SqlHelper.execute(getEntityClass(queryWrapper), baseMapper -> SqlHelper.getObject(log, baseMapper.selectMaps(queryWrapper)));
+    }
+
+    /**
+     * 查询总记录数
+     *
+     * @param entityClass 实体类
+     * @see Wrappers#emptyWrapper()
+     */
+    public static <T> long count(Class<T> entityClass) {
+        return SqlHelper.execute(entityClass, baseMapper -> baseMapper.selectCount(null));
+    }
+
+    /**
+     * 根据 Wrapper 条件,查询总记录数
+     *
+     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
+     */
+    public static <T> long count(AbstractWrapper<T, ?, ?> queryWrapper) {
+        return SqlHelper.execute(getEntityClass(queryWrapper), baseMapper -> baseMapper.selectCount(queryWrapper));
+    }
+
+    /**
+     * 查询列表
+     *
+     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
+     */
+    public static <T> List<T> list(AbstractWrapper<T, ?, ?> queryWrapper) {
+        Class<T> entityClass = getEntityClass(queryWrapper);
+        return SqlHelper.execute(entityClass, baseMapper -> baseMapper.selectList(queryWrapper));
+    }
+
+    /**
+     * 查询所有
+     *
+     * @param entityClass 实体类
+     * @see Wrappers#emptyWrapper()
+     */
+    public static <T> List<T> list(Class<T> entityClass) {
+        return SqlHelper.execute(entityClass, baseMapper -> baseMapper.selectList(null));
+    }
+
+    /**
+     * 查询列表
+     *
+     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
+     */
+    public static <T> List<Map<String, Object>> listMaps(AbstractWrapper<T, ?, ?> queryWrapper) {
+        return SqlHelper.execute(getEntityClass(queryWrapper), baseMapper -> baseMapper.selectMaps(queryWrapper));
+    }
+
+    /**
+     * 查询所有列表
+     *
+     * @param entityClass 实体类
+     * @see Wrappers#emptyWrapper()
+     */
+    public static <T> List<Map<String, Object>> listMaps(Class<T> entityClass) {
+        return SqlHelper.execute(entityClass, baseMapper -> baseMapper.selectMaps(null));
+    }
+
+    /**
+     * 查询全部记录
+     *
+     * @param entityClass 实体类
+     */
+    public static <T> List<T> listObjs(Class<T> entityClass) {
+        return listObjs(entityClass, i -> i);
+    }
+
+    /**
+     * 根据 Wrapper 条件,查询全部记录
+     *
+     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
+     */
+    public static <T> List<Object> listObjs(AbstractWrapper<T, ?, ?> queryWrapper) {
+        return SqlHelper.execute(getEntityClass(queryWrapper), baseMapper -> baseMapper.selectObjs(queryWrapper));
+    }
+
+    /**
+     * 根据 Wrapper 条件,查询全部记录
+     *
+     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
+     * @param mapper       转换函数
+     */
+    public static <T, V> List<V> listObjs(AbstractWrapper<T, ?, ?> queryWrapper, SFunction<? super T, V> mapper) {
+        return SqlHelper.execute(getEntityClass(queryWrapper), baseMapper -> baseMapper.selectList(queryWrapper).stream().map(mapper).collect(Collectors.toList()));
+    }
+
+    /**
+     * 查询全部记录
+     *
+     * @param entityClass 实体类
+     * @param mapper      转换函数
+     */
+    public static <T, V> List<V> listObjs(Class<T> entityClass, SFunction<? super T, V> mapper) {
+        return SqlHelper.execute(entityClass, baseMapper -> baseMapper.selectList(null).stream().map(mapper).collect(Collectors.toList()));
+    }
+
+    /**
+     * 无条件翻页查询
+     *
+     * @param page        翻页对象
+     * @param entityClass 实体类
+     * @see Wrappers#emptyWrapper()
+     */
+    public static <T, E extends IPage<Map<String, Object>>> E pageMaps(E page, Class<T> entityClass) {
+        return SqlHelper.execute(entityClass, baseMapper -> baseMapper.selectMapsPage(page, null));
+    }
+
+    /**
+     * 翻页查询
+     *
+     * @param page         翻页对象
+     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
+     */
+    public static <T, E extends IPage<Map<String, Object>>> E pageMaps(E page, AbstractWrapper<T, ?, ?> queryWrapper) {
+        return SqlHelper.execute(getEntityClass(queryWrapper), baseMapper -> baseMapper.selectMapsPage(page, queryWrapper));
+    }
+
+    /**
+     * 无条件翻页查询
+     *
+     * @param page        翻页对象
+     * @param entityClass 实体类
+     * @see Wrappers#emptyWrapper()
+     */
+    public static <T> IPage<T> page(IPage<T> page, Class<T> entityClass) {
+        return SqlHelper.execute(entityClass, baseMapper -> baseMapper.selectPage(page, null));
+    }
+
+    /**
+     * 翻页查询
+     *
+     * @param page         翻页对象
+     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
+     */
+    public static <T> IPage<T> page(IPage<T> page, AbstractWrapper<T, ?, ?> queryWrapper) {
+        return SqlHelper.execute(getEntityClass(queryWrapper), baseMapper -> baseMapper.selectPage(page, queryWrapper));
+    }
+
+    /**
+     * 链式查询 普通
+     *
+     * @return QueryWrapper 的包装类
+     */
+    public static <T> QueryChainWrapper<T> query(Class<T> entityClass) {
+        return ChainWrappers.queryChain(entityClass);
+    }
+
+    /**
+     * 链式查询 lambda 式
+     * <p>注意:不支持 Kotlin </p>
+     *
+     * @return LambdaQueryWrapper 的包装类
+     */
+    public static <T> LambdaQueryChainWrapper<T> lambdaQuery(Class<T> entityClass) {
+        return ChainWrappers.lambdaQueryChain(entityClass);
+    }
+
+    /**
+     * 链式更改 普通
+     *
+     * @return UpdateWrapper 的包装类
+     */
+    public static <T> UpdateChainWrapper<T> update(Class<T> entityClass) {
+        return ChainWrappers.updateChain(entityClass);
+    }
+
+    /**
+     * 链式更改 lambda 式
+     * <p>注意:不支持 Kotlin </p>
+     *
+     * @return LambdaUpdateWrapper 的包装类
+     */
+    public static <T> LambdaUpdateChainWrapper<T> lambdaUpdate(Class<T> entityClass) {
+        return ChainWrappers.lambdaUpdateChain(entityClass);
+    }
+
+    /**
+     * <p>
+     * 根据updateWrapper尝试更新,否继续执行saveOrUpdate(T)方法
+     * 此次修改主要是减少了此项业务代码的代码量(存在性验证之后的saveOrUpdate操作)
+     * </p>
+     *
+     * @param entity 实体对象
+     */
+    public static <T> boolean saveOrUpdate(T entity, AbstractWrapper<T, ?, ?> updateWrapper) {
+        return update(entity, updateWrapper) || saveOrUpdate(entity);
+    }
+
+    /**
+     * 根据 Wrapper,查询一条记录
+     *
+     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
+     * @param mapper       转换函数
+     */
+    public static <T, V> V getObj(AbstractWrapper<T, ?, ?> queryWrapper, SFunction<? super T, V> mapper) {
+        return SqlHelper.execute(getEntityClass(queryWrapper), baseMapper -> mapper.apply(baseMapper.selectOne(queryWrapper)));
+    }
+
+    /**
+     * 从集合中获取实体类型
+     *
+     * @param entityList 实体集合
+     * @param <T>        实体类型
+     * @return 实体类型
+     */
+    @SuppressWarnings("unchecked")
+    private static <T> Class<T> getEntityClass(Collection<T> entityList) {
+        Class<T> entityClass = null;
+        for (T entity : entityList) {
+            if (entity != null && entity.getClass() != null) {
+                entityClass = (Class<T>) entity.getClass();
+                break;
+            }
+        }
+        Assert.notNull(entityClass, "error: can not get entityClass from entityList");
+        return entityClass;
+    }
+
+    /**
+     * 从wrapper中尝试获取实体类型
+     *
+     * @param queryWrapper 条件构造器
+     * @param <T>          实体类型
+     * @return 实体类型
+     */
+    @SuppressWarnings("unchecked")
+    private static <T> Class<T> getEntityClass(AbstractWrapper<T, ?, ?> queryWrapper) {
+        Class<T> entityClass = queryWrapper.getEntityClass();
+        if (entityClass == null) {
+            T entity = queryWrapper.getEntity();
+            if (entity != null) {
+                entityClass = (Class<T>) entity.getClass();
+            }
+        }
+        Assert.notNull(entityClass, "error: can not get entityClass from wrapper");
+        return entityClass;
+    }
+
+    /**
+     * 获取表信息,获取不到报错提示
+     *
+     * @param entityClass 实体类
+     * @param <T>         实体类型
+     * @return 对应表信息
+     */
+    private static <T> TableInfo getTableInfo(Class<T> entityClass) {
+        return Optional.ofNullable(TableInfoHelper.getTableInfo(entityClass)).orElseThrow(() -> ExceptionUtils.mpe("error: can not find TableInfo from Class: \"%s\".", entityClass.getName()));
+    }
+}

+ 4 - 0
mybatis-plus-extension/src/main/kotlin/com/baomidou/mybatisplus/extension/kotlin/KtQueryChainWrapper.kt

@@ -55,4 +55,8 @@ open class KtQueryChainWrapper<T : Any>(
         return baseMapper
         return baseMapper
     }
     }
 
 
+    override fun getEntityClass(): Class<T> {
+        return super.wrapperChildren.entityClass
+    }
+
 }
 }

+ 4 - 0
mybatis-plus-extension/src/main/kotlin/com/baomidou/mybatisplus/extension/kotlin/KtUpdateChainWrapper.kt

@@ -53,4 +53,8 @@ open class KtUpdateChainWrapper<T : Any>(
         return baseMapper
         return baseMapper
     }
     }
 
 
+    override fun getEntityClass(): Class<T> {
+        return super.wrapperChildren.entityClass
+    }
+
 }
 }

+ 46 - 0
mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/chainwrapper/ChainWrappersTest.java

@@ -0,0 +1,46 @@
+package com.baomidou.mybatisplus.test.chainwrapper;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import com.baomidou.mybatisplus.extension.toolkit.ChainWrappers;
+import com.baomidou.mybatisplus.test.BaseDbTest;
+
+/**
+ * @author VampireAchao
+ * @since 2022-04-18
+ */
+public class ChainWrappersTest extends BaseDbTest<EntityMapper> {
+
+    @Test
+    void test() {
+        final String id = "id";
+        Entity entity = new Entity();
+        Assertions.assertAll(() -> ChainWrappers.queryChain(entity.getClass())
+            .func(j -> j.isNotNull(id))
+            .func(entity.getId() != null, j -> j.eq("id", entity.getId()))// 不会npe,也不会加入sql
+            .and(j -> j.isNotNull(id))
+            .or(j -> j.isNotNull(id))
+            .nested(j -> j.isNotNull(id))
+            .not(j -> j.isNull(id))
+            .list());
+
+    }
+
+    @Override
+    protected String tableDataSql() {
+        return "insert into entity(id,name) values(1,'1'),(2,'2');";
+    }
+
+    @Override
+    protected List<String> tableSql() {
+        return Arrays.asList("drop table if exists entity", "CREATE TABLE IF NOT EXISTS entity (" +
+            "id BIGINT NOT NULL," +
+            "name VARCHAR(30) NULL DEFAULT NULL," +
+            "PRIMARY KEY (id))");
+    }
+}
+

+ 275 - 0
mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/toolkit/DbTest.java

@@ -0,0 +1,275 @@
+package com.baomidou.mybatisplus.test.toolkit;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ibatis.plugin.Interceptor;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import com.baomidou.mybatisplus.annotation.DbType;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
+import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper;
+import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
+import com.baomidou.mybatisplus.extension.conditions.update.UpdateChainWrapper;
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.toolkit.Db;
+import com.baomidou.mybatisplus.test.BaseDbTest;
+import com.baomidou.mybatisplus.test.sqlrunner.Entity;
+import com.baomidou.mybatisplus.test.sqlrunner.EntityMapper;
+
+/**
+ * 以静态方式调用Service中的函数
+ *
+ * @author VampireAchao
+ * @since 2022-05-03
+ */
+class DbTest extends BaseDbTest<EntityMapper> {
+
+    @Test
+    void testSave() {
+        Entity entity = new Entity();
+        entity.setName("ruben");
+        boolean isSuccess = Db.save(entity);
+        Assertions.assertTrue(isSuccess);
+        Assertions.assertEquals(3L, Db.count(Entity.class));
+    }
+
+    @Test
+    void testSaveBatch() {
+        List<Entity> list = Arrays.asList(new Entity(), new Entity());
+        boolean isSuccess = Db.saveBatch(list);
+        Assertions.assertTrue(isSuccess);
+        Assertions.assertEquals(4, Db.count(Entity.class));
+    }
+
+    @Test
+    void testSaveOrUpdateBatch() {
+        Entity entity = new Entity();
+        entity.setId(1L);
+        entity.setName("cat");
+        List<Entity> list = Arrays.asList(new Entity(), entity);
+        boolean isSuccess = Db.saveOrUpdateBatch(list);
+        Assertions.assertTrue(isSuccess);
+        Assertions.assertEquals(3, Db.count(Entity.class));
+    }
+
+    @Test
+    void testRemoveById() {
+        Entity entity = new Entity();
+        entity.setId(1L);
+        boolean isSuccess = Db.removeById(entity);
+        Assertions.assertTrue(isSuccess);
+        Assertions.assertEquals(1, Db.count(Entity.class));
+        isSuccess = Db.removeById(2L, Entity.class);
+        Assertions.assertTrue(isSuccess);
+        Assertions.assertEquals(0, Db.count(Entity.class));
+    }
+
+    @Test
+    void testUpdateById() {
+        Entity entity = new Entity();
+        entity.setId(1L);
+        entity.setName("bee bee I'm a sheep");
+        boolean isSuccess = Db.updateById(entity);
+        Assertions.assertTrue(isSuccess);
+        Assertions.assertEquals("bee bee I'm a sheep", Db.getById(1L, Entity.class).getName());
+    }
+
+    @Test
+    void testUpdate() {
+        boolean isSuccess = Db.update(Wrappers.lambdaUpdate(Entity.class).eq(Entity::getId, 1L).set(Entity::getName, "be better"));
+        Assertions.assertTrue(isSuccess);
+        Assertions.assertEquals("be better", Db.getById(1L, Entity.class).getName());
+
+        Entity entity = new Entity();
+        entity.setId(1L);
+        entity.setName("bee bee I'm a sheep");
+        isSuccess = Db.update(entity, Wrappers.lambdaQuery(Entity.class).eq(Entity::getId, 1L));
+        Assertions.assertTrue(isSuccess);
+        Assertions.assertEquals("bee bee I'm a sheep", Db.getById(1L, Entity.class).getName());
+    }
+
+    @Test
+    void testUpdateBatchById() {
+        Entity sheep = new Entity();
+        sheep.setId(1L);
+        sheep.setName("bee bee I'm a sheep");
+
+        Entity ruben = new Entity();
+        ruben.setId(2L);
+        ruben.setName("rabbit");
+        boolean isSuccess = Db.updateBatchById(Arrays.asList(sheep, ruben));
+        Assertions.assertTrue(isSuccess);
+        Assertions.assertEquals("bee bee I'm a sheep", Db.getById(1L, Entity.class).getName());
+        Assertions.assertEquals("rabbit", Db.getById(2L, Entity.class).getName());
+    }
+
+    @Test
+    void testRemove() {
+        boolean isSuccess = Db.remove(Wrappers.lambdaQuery(Entity.class).eq(Entity::getId, 1L));
+        Assertions.assertTrue(isSuccess);
+        Assertions.assertEquals(1, Db.count(Entity.class));
+    }
+
+    @Test
+    void testRemoveByIds() {
+        boolean isSuccess = Db.removeByIds(Arrays.asList(1L, 2L), Entity.class);
+        Assertions.assertTrue(isSuccess);
+        Assertions.assertEquals(0, Db.count(Entity.class));
+    }
+
+    @Test
+    void testRemoveByMap() {
+        boolean isSuccess = Db.removeByMap(Collections.singletonMap("id", 1L), Entity.class);
+        Assertions.assertTrue(isSuccess);
+        Assertions.assertEquals(1, Db.count(Entity.class));
+    }
+
+    @Test
+    void testSaveOrUpdate() {
+        Entity entity = new Entity();
+        entity.setId(null);
+        entity.setName("bee bee I'm a sheep");
+        boolean isSuccess = Db.saveOrUpdate(entity);
+        Assertions.assertTrue(isSuccess);
+        Assertions.assertEquals("bee bee I'm a sheep", Db.getById(entity.getId(), Entity.class).getName());
+
+        entity.setName("be better");
+        isSuccess = Db.saveOrUpdate(entity, Wrappers.lambdaQuery(Entity.class).eq(Entity::getId, entity.getId()));
+        Assertions.assertTrue(isSuccess);
+        Assertions.assertEquals("be better", Db.getById(entity.getId(), Entity.class).getName());
+    }
+
+    @Test
+    void testGetOne() {
+        LambdaQueryWrapper<Entity> wrapper = Wrappers.lambdaQuery(Entity.class);
+        Assertions.assertThrows(MybatisPlusException.class, () -> Db.getOne(wrapper));
+        Entity one = Db.getOne(wrapper, false);
+        Assertions.assertNotNull(one);
+    }
+
+    @Test
+    void testListByMap() {
+        Map<String, Object> map = new HashMap<>();
+        map.put("id", 1L);
+        List<Entity> list = Db.listByMap(map, Entity.class);
+        Assertions.assertEquals(1, list.size());
+        Assertions.assertEquals("ruben", list.get(0).getName());
+    }
+
+    @Test
+    void testByIds() {
+        List<Entity> list = Db.listByIds(Arrays.asList(1L, 2L), Entity.class);
+        Assertions.assertEquals(2, list.size());
+    }
+
+    @Test
+    void testGetMap() {
+        Map<String, Object> map = Db.getMap(Wrappers.lambdaQuery(Entity.class));
+        Assertions.assertNotNull(map);
+    }
+
+    @Test
+    void testList() {
+        List<Entity> list = Db.list(Wrappers.lambdaQuery(Entity.class));
+        Assertions.assertEquals(2, list.size());
+
+        list = Db.list(Entity.class);
+        Assertions.assertEquals(2, list.size());
+    }
+
+    @Test
+    void testListMaps() {
+        List<Map<String, Object>> list = Db.listMaps(Wrappers.lambdaQuery(Entity.class));
+        Assertions.assertEquals(2, list.size());
+
+        list = Db.listMaps(Entity.class);
+        Assertions.assertEquals(2, list.size());
+    }
+
+    @Test
+    void testListObjs() {
+        List<Entity> list = Db.listObjs(Entity.class);
+        Assertions.assertEquals(2, list.size());
+
+        List<Long> objectList = Db.listObjs(Wrappers.lambdaQuery(Entity.class), Entity::getId);
+        Assertions.assertEquals(2, objectList.size());
+
+        List<String> names = Db.listObjs(Entity.class, Entity::getName);
+        Assertions.assertArrayEquals(new String[]{"ruben", "chocolate"}, names.toArray());
+    }
+
+    @Override
+    protected List<Interceptor> interceptors() {
+        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
+        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.SQLITE));
+        return Collections.singletonList(interceptor);
+    }
+
+    @Test
+    void testPageMaps() {
+        Page<Map<String, Object>> page = Db.pageMaps(new Page<>(1, 1), Entity.class);
+        Assertions.assertEquals(2, page.getTotal());
+
+        page = Db.pageMaps(new Page<>(1, 1), Wrappers.lambdaQuery(Entity.class));
+        Assertions.assertEquals(1, page.getRecords().size());
+    }
+
+    @Test
+    void testPage() {
+        IPage<Entity> page = Db.page(new Page<>(1, 1), Entity.class);
+        Assertions.assertEquals(2, page.getTotal());
+
+        page = Db.page(new Page<>(1, 1), Wrappers.lambdaQuery(Entity.class));
+        Assertions.assertEquals(1, page.getRecords().size());
+    }
+
+    @Test
+    void testChain() {
+        QueryChainWrapper<Entity> query = Db.query(Entity.class);
+        List<Entity> list = query.eq("id", 1L).list();
+        Assertions.assertEquals(1, list.size());
+
+        LambdaQueryChainWrapper<Entity> lambdaQuery = Db.lambdaQuery(Entity.class);
+        list = lambdaQuery.eq(Entity::getId, 1L).list();
+        Assertions.assertEquals(1, list.size());
+
+        UpdateChainWrapper<Entity> update = Db.update(Entity.class);
+        update.eq("id", 1L).set("name", "bee bee I'm a sheep").update();
+        Assertions.assertEquals("bee bee I'm a sheep", lambdaQuery.eq(Entity::getId, 1L).one().getName());
+
+        LambdaUpdateChainWrapper<Entity> lambdaUpdate = Db.lambdaUpdate(Entity.class);
+        lambdaUpdate.eq(Entity::getId, 1L).set(Entity::getName, "be better").update();
+        Assertions.assertEquals("be better", lambdaQuery.eq(Entity::getId, 1L).one().getName());
+    }
+
+    @Test
+    void testGetObj() {
+        String name = Db.getObj(Wrappers.lambdaQuery(Entity.class).eq(Entity::getId, 1L), Entity::getName);
+        Assertions.assertEquals("ruben", name);
+    }
+
+
+    @Override
+    protected String tableDataSql() {
+        return "insert into entity(id,name) values(1,'ruben'),(2,'chocolate');";
+    }
+
+    @Override
+    protected List<String> tableSql() {
+        return Arrays.asList("drop table if exists entity", "CREATE TABLE IF NOT EXISTS entity (" +
+            "id BIGINT NOT NULL," +
+            "name VARCHAR(30) NULL DEFAULT NULL," +
+            "PRIMARY KEY (id))");
+    }
+}