浏览代码

新增 StaticService,用于 以静态方式调用Service中的函数

VampireAchao 3 年之前
父节点
当前提交
433648ff00

+ 568 - 0
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/toolkit/StaticService.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 StaticService {
+
+    /**
+     * 默认批次提交数量
+     */
+    public static final int DEFAULT_BATCH_SIZE = 1000;
+    private static final Log log = LogFactory.getLog(StaticService.class);
+
+    private StaticService() {
+        /* 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(StaticService.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(StaticService.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(StaticService.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()));
+    }
+}

+ 275 - 0
mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/toolkit/StaticServiceTest.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.StaticService;
+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 StaticServiceTest extends BaseDbTest<EntityMapper> {
+
+    @Test
+    void testSave() {
+        Entity entity = new Entity();
+        entity.setName("ruben");
+        boolean isSuccess = StaticService.save(entity);
+        Assertions.assertTrue(isSuccess);
+        Assertions.assertEquals(3L, StaticService.count(Entity.class));
+    }
+
+    @Test
+    void testSaveBatch() {
+        List<Entity> list = Arrays.asList(new Entity(), new Entity());
+        boolean isSuccess = StaticService.saveBatch(list);
+        Assertions.assertTrue(isSuccess);
+        Assertions.assertEquals(4, StaticService.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 = StaticService.saveOrUpdateBatch(list);
+        Assertions.assertTrue(isSuccess);
+        Assertions.assertEquals(3, StaticService.count(Entity.class));
+    }
+
+    @Test
+    void testRemoveById() {
+        Entity entity = new Entity();
+        entity.setId(1L);
+        boolean isSuccess = StaticService.removeById(entity);
+        Assertions.assertTrue(isSuccess);
+        Assertions.assertEquals(1, StaticService.count(Entity.class));
+        isSuccess = StaticService.removeById(2L, Entity.class);
+        Assertions.assertTrue(isSuccess);
+        Assertions.assertEquals(0, StaticService.count(Entity.class));
+    }
+
+    @Test
+    void testUpdateById() {
+        Entity entity = new Entity();
+        entity.setId(1L);
+        entity.setName("bee bee I'm a sheep");
+        boolean isSuccess = StaticService.updateById(entity);
+        Assertions.assertTrue(isSuccess);
+        Assertions.assertEquals("bee bee I'm a sheep", StaticService.getById(1L, Entity.class).getName());
+    }
+
+    @Test
+    void testUpdate() {
+        boolean isSuccess = StaticService.update(Wrappers.lambdaUpdate(Entity.class).eq(Entity::getId, 1L).set(Entity::getName, "be better"));
+        Assertions.assertTrue(isSuccess);
+        Assertions.assertEquals("be better", StaticService.getById(1L, Entity.class).getName());
+
+        Entity entity = new Entity();
+        entity.setId(1L);
+        entity.setName("bee bee I'm a sheep");
+        isSuccess = StaticService.update(entity, Wrappers.lambdaQuery(Entity.class).eq(Entity::getId, 1L));
+        Assertions.assertTrue(isSuccess);
+        Assertions.assertEquals("bee bee I'm a sheep", StaticService.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 = StaticService.updateBatchById(Arrays.asList(sheep, ruben));
+        Assertions.assertTrue(isSuccess);
+        Assertions.assertEquals("bee bee I'm a sheep", StaticService.getById(1L, Entity.class).getName());
+        Assertions.assertEquals("rabbit", StaticService.getById(2L, Entity.class).getName());
+    }
+
+    @Test
+    void testRemove() {
+        boolean isSuccess = StaticService.remove(Wrappers.lambdaQuery(Entity.class).eq(Entity::getId, 1L));
+        Assertions.assertTrue(isSuccess);
+        Assertions.assertEquals(1, StaticService.count(Entity.class));
+    }
+
+    @Test
+    void testRemoveByIds() {
+        boolean isSuccess = StaticService.removeByIds(Arrays.asList(1L, 2L), Entity.class);
+        Assertions.assertTrue(isSuccess);
+        Assertions.assertEquals(0, StaticService.count(Entity.class));
+    }
+
+    @Test
+    void testRemoveByMap() {
+        boolean isSuccess = StaticService.removeByMap(Collections.singletonMap("id", 1L), Entity.class);
+        Assertions.assertTrue(isSuccess);
+        Assertions.assertEquals(1, StaticService.count(Entity.class));
+    }
+
+    @Test
+    void testSaveOrUpdate() {
+        Entity entity = new Entity();
+        entity.setId(null);
+        entity.setName("bee bee I'm a sheep");
+        boolean isSuccess = StaticService.saveOrUpdate(entity);
+        Assertions.assertTrue(isSuccess);
+        Assertions.assertEquals("bee bee I'm a sheep", StaticService.getById(entity.getId(), Entity.class).getName());
+
+        entity.setName("be better");
+        isSuccess = StaticService.saveOrUpdate(entity, Wrappers.lambdaQuery(Entity.class).eq(Entity::getId, entity.getId()));
+        Assertions.assertTrue(isSuccess);
+        Assertions.assertEquals("be better", StaticService.getById(entity.getId(), Entity.class).getName());
+    }
+
+    @Test
+    void testGetOne() {
+        LambdaQueryWrapper<Entity> wrapper = Wrappers.lambdaQuery(Entity.class);
+        Assertions.assertThrows(MybatisPlusException.class, () -> StaticService.getOne(wrapper));
+        Entity one = StaticService.getOne(wrapper, false);
+        Assertions.assertNotNull(one);
+    }
+
+    @Test
+    void testListByMap() {
+        Map<String, Object> map = new HashMap<>();
+        map.put("id", 1L);
+        List<Entity> list = StaticService.listByMap(map, Entity.class);
+        Assertions.assertEquals(1, list.size());
+        Assertions.assertEquals("ruben", list.get(0).getName());
+    }
+
+    @Test
+    void testByIds() {
+        List<Entity> list = StaticService.listByIds(Arrays.asList(1L, 2L), Entity.class);
+        Assertions.assertEquals(2, list.size());
+    }
+
+    @Test
+    void testGetMap() {
+        Map<String, Object> map = StaticService.getMap(Wrappers.lambdaQuery(Entity.class));
+        Assertions.assertNotNull(map);
+    }
+
+    @Test
+    void testList() {
+        List<Entity> list = StaticService.list(Wrappers.lambdaQuery(Entity.class));
+        Assertions.assertEquals(2, list.size());
+
+        list = StaticService.list(Entity.class);
+        Assertions.assertEquals(2, list.size());
+    }
+
+    @Test
+    void testListMaps() {
+        List<Map<String, Object>> list = StaticService.listMaps(Wrappers.lambdaQuery(Entity.class));
+        Assertions.assertEquals(2, list.size());
+
+        list = StaticService.listMaps(Entity.class);
+        Assertions.assertEquals(2, list.size());
+    }
+
+    @Test
+    void testListObjs() {
+        List<Entity> list = StaticService.listObjs(Entity.class);
+        Assertions.assertEquals(2, list.size());
+
+        List<Long> objectList = StaticService.listObjs(Wrappers.lambdaQuery(Entity.class), Entity::getId);
+        Assertions.assertEquals(2, objectList.size());
+
+        List<String> names = StaticService.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 = StaticService.pageMaps(new Page<>(1, 1), Entity.class);
+        Assertions.assertEquals(2, page.getTotal());
+
+        page = StaticService.pageMaps(new Page<>(1, 1), Wrappers.lambdaQuery(Entity.class));
+        Assertions.assertEquals(1, page.getRecords().size());
+    }
+
+    @Test
+    void testPage() {
+        IPage<Entity> page = StaticService.page(new Page<>(1, 1), Entity.class);
+        Assertions.assertEquals(2, page.getTotal());
+
+        page = StaticService.page(new Page<>(1, 1), Wrappers.lambdaQuery(Entity.class));
+        Assertions.assertEquals(1, page.getRecords().size());
+    }
+
+    @Test
+    void testChain() {
+        QueryChainWrapper<Entity> query = StaticService.query(Entity.class);
+        List<Entity> list = query.eq("id", 1L).list();
+        Assertions.assertEquals(1, list.size());
+
+        LambdaQueryChainWrapper<Entity> lambdaQuery = StaticService.lambdaQuery(Entity.class);
+        list = lambdaQuery.eq(Entity::getId, 1L).list();
+        Assertions.assertEquals(1, list.size());
+
+        UpdateChainWrapper<Entity> update = StaticService.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 = StaticService.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 = StaticService.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))");
+    }
+}