---
url: /diary/wauoktu5/index.md
description: 使用 Java Optional 优化 MyBatis-Plus 查询结果处理，避免空指针异常，提升代码健壮性。
---
> 使用Optional增强Mybatis-plus体验

## MyBatis-Plus

`MyBatis-Plus`（简称MP）是`MyBatis`社区的一个增强工具包，它在`MyBatis`的基础上进行了扩展，封装了很多有用的功能，提高了开发效率。`MyBatis-Plus`中包含了许多常用的增删改查的方法，还有分页查询、条件构造器、乐观锁、多租户、性能分析等功能。

以下是`MyBatis-Plus`的一些特点：

1. 简化开发：`MyBatis-Plus`可以通过代码自动生成器快速生成CRUD方法的代码，极大地提高了开发效率。
2. 增删改查方法：`MyBatis-Plus`封装了通用的增删改查方法，无需手写SQL语句。
3. 集成分页插件：`MyBatis-Plus`集成了分页插件，使用简单，可以轻松实现分页操作。
4. 条件构造器：`MyBatis-Plus`提供了条件构造器，可以通过代码的形式构造复杂的SQL查询语句。
5. 乐观锁：`MyBatis-Plus`提供了乐观锁的功能，避免了并发操作时的数据冲突。
6. 多租户：`MyBatis-Plus`支持多租户，可以通过配置实现多租户系统的开发。
7. 性能分析：`MyBatis-Plus`集成了性能分析插件，可以分析SQL查询的性能瓶颈，帮助优化SQL语句，提高查询效率。

总之，`MyBatis-Plus`是一个非常优秀的`MyBatis`增强工具包，其功能强大且易于使用，在实际开发中也能够显著地提高开发效率和工作效率。

## Java Optional

`Java Optional`是`Java 8`中引入的一个类，用于表示一个值可能存在也可能不存在。它的主要目的是减少空指针异常。

`Java Optional`类有两个重要的方法:`isPresent()`和`get()`。`isPresent()`方法用于检查值是否存在，`get()`方法用于获取值。如果值不存在，`get()`方法会抛出`NoSuchElementException`异常。

`Java Optional`还有很多有用的方法，比如`orElse()`和`orElseGet()`方法。这些方法可以帮助我们处理值不存在的情况。

`Java Optional`是一个泛型类，因此可以用于处理任何类型的值。使用`Java Optional`的主要优点是可以避免空指针异常，提高代码健壮性。

## 堵点

`MyBatis-Plus`提供了很好的`CURD`体验，大大加强了开发的效率，其`Lambda`表达式式的方式也大大增强了用户的体验，但是`MyBatis-Plus`返回的参数仍然会在实际项目中被忽略空指针问题，笔者的朋友和同事就经常因为空指针问题（主要是忘记）经常被测试吐槽，故此通过可以使用`Optional`来增强`Mybatis-plus`的体验，一定程度上可以避免“忘记”判空带来的空指针问题。

## 代码

项目中引入`MyBatis-Plus`，新建`OptionalBaseMapper`文件，实现`BaseMapper`，具体代码如下：

```java :collapsed-lines
@SuppressWarnings({"DuplicatedCode", "unused"})
public interface OptionalBaseMapper<T> extends BaseMapper<T> {

    // ======================================= 批量插入 ========================================

    /**
     * 批量插入 仅适用于mysql
     *
     * @param entityList 实体列表
     * @return 影响行数
     */
    Integer insertBatchSomeColumn(Collection<T> entityList);

    /**
     * 逐条插入，适合少量数据插入，或者对性能要求不高的场景
     * <p>
     * 如果大量，请使用 {@link com.baomidou.mybatisplus.extension.service.impl.ServiceImpl#saveBatch(Collection)} 方法
     * 使用示例，可见 RoleMenuBatchInsertMapper、UserRoleBatchInsertMapper 类
     *
     * @param entities 实体们
     */
    default void insertBatch(Collection<T> entities) {
        entities.forEach(this::insert);
    }

    // ======================================= 查询数量 ========================================


    /**
     * 根据 Wrapper 条件，查询总记录数
     *
     * @param queryWrapper 实体对象封装操作类（可以为 null）
     */
    default Optional<Long> getCount(Wrapper<T> queryWrapper) {
        Long count = selectCount(queryWrapper);
        return ObjectUtil.isNull(count) ? Optional.empty() : Optional.of(count);
    }

    /**
     * 查询指定字段值数量
     *
     * @param field field
     * @param value value
     */
    default Optional<Long> selectCount(String field, Object value) {
        Long count = selectCount(new QueryWrapper<T>().eq(field, value));
        return ObjectUtil.isNull(count) ? Optional.empty() : Optional.of(count);
    }

    /**
     * 查询指定字段值数量
     *
     * @param field field
     * @param value value
     */
    default Optional<Long> selectCount(SFunction<T, ?> field, Object value) {
        Long count = selectCount(new LambdaQueryWrapper<T>().eq(field, value));
        return ObjectUtil.isNull(count) ? Optional.empty() : Optional.of(count);
    }

    // ======================================= 查询一个 ========================================


    /**
     * 根据 ID 查询
     *
     * @param id 主键ID
     */
    default Optional<T> getById(Serializable id) {
        T t = selectById(id);
        return ObjectUtil.isNull(t) ? Optional.empty() : Optional.of(t);
    }


    /**
     * 根据 entity 条件，查询一条记录
     * <p>查询一条记录，例如 qw.last("limit 1") 限制取一条记录, 注意：多条数据会报异常</p>
     *
     * @param queryWrapper 实体对象封装操作类（可以为 null）
     */
    default Optional<T> getOne(Wrapper<T> queryWrapper) {
        T t = selectOne(queryWrapper);
        return ObjectUtil.isNull(t) ? Optional.empty() : Optional.of(t);
    }

    /**
     * 查询一个
     *
     * @param field field
     * @param value value
     */
    default Optional<T> getOne(String field, Object value) {
        return getOne(new QueryWrapper<T>().eq(field, value));
    }

    /**
     * 查询一个
     *
     * @param field field
     * @param value value
     */
    default Optional<T> getOne(SFunction<T, ?> field, Object value) {
        return getOne(new LambdaQueryWrapper<T>().eq(field, value));
    }

    /**
     * 查询一个
     *
     * @param field1 field1
     * @param value1 value1
     * @param field2 field2
     * @param value2 value2
     */
    default Optional<T> getTwo(String field1, Object value1, String field2, Object value2) {
        return getOne(new QueryWrapper<T>().eq(field1, value1).eq(field2, value2));
    }

    /**
     * 查询一个
     *
     * @param field1 field1
     * @param value1 value1
     * @param field2 field2
     * @param value2 value2
     */
    default Optional<T> getTwo(SFunction<T, ?> field1, Object value1, SFunction<T, ?> field2, Object value2) {
        return getOne(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2));
    }


    // ======================================= 查询多个 ========================================


    /**
     * 查询（根据ID 批量查询）
     *
     * @param idList 主键ID列表(不能为 null 以及 empty)
     */
    default Optional<List<T>> listBatchIds(Collection<? extends Serializable> idList) {
        List<T> list = selectBatchIds(idList);
        return CollUtil.isEmpty(list) ? Optional.empty() : Optional.of(list);
    }

    /**
     * 根据 entity 条件，查询全部记录
     *
     * @param queryWrapper 实体对象封装操作类（可以为 null）
     */
    default Optional<List<T>> list(Wrapper<T> queryWrapper) {
        List<T> list = selectList(queryWrapper);
        return CollUtil.isEmpty(list) ? Optional.empty() : Optional.of(list);
    }

    /**
     * 列表查询
     *
     * @param field field
     * @param value value
     */
    default Optional<List<T>> list(String field, Object value) {
        List<T> list = selectList(new QueryWrapper<T>().eq(field, value));
        return CollUtil.isEmpty(list) ? Optional.empty() : Optional.of(list);
    }

    /**
     * 列表查询
     *
     * @param field field
     * @param value value
     */
    default Optional<List<T>> list(SFunction<T, ?> field, Object value) {
        List<T> list = selectList(new LambdaQueryWrapper<T>().eq(field, value));
        return CollUtil.isEmpty(list) ? Optional.empty() : Optional.of(list);
    }

    /**
     * 列表查询
     *
     * @param field  field
     * @param values values
     */
    default Optional<List<T>> list(String field, Collection<?> values) {
        List<T> list = selectList(new QueryWrapper<T>().in(field, values));
        return CollUtil.isEmpty(list) ? Optional.empty() : Optional.of(list);
    }

    /**
     * 列表查询
     *
     * @param field  field
     * @param values values
     */
    default Optional<List<T>> list(SFunction<T, ?> field, Collection<?> values) {
        List<T> list = selectList(new LambdaQueryWrapper<T>().in(field, values));
        return CollUtil.isEmpty(list) ? Optional.empty() : Optional.of(list);
    }


    /**
     * 查询（根据 columnMap 条件）
     *
     * @param columnMap 表字段 map 对象
     */
    default Optional<List<T>> listByMaps(Map<String, Object> columnMap) {
        List<T> list = selectByMap(columnMap);
        return CollUtil.isEmpty(list) ? Optional.empty() : Optional.of(list);
    }

    /**
     * 根据 Wrapper 条件，查询全部记录
     *
     * @param queryWrapper 实体对象封装操作类（可以为 null）
     */
    default Optional<List<Map<String, Object>>> maps(Wrapper<T> queryWrapper) {
        List<Map<String, Object>> maps = selectMaps(queryWrapper);
        return CollUtil.isEmpty(maps) ? Optional.empty() : Optional.of(maps);
    }

    /**
     * 根据 Wrapper 条件，查询全部记录
     * <p>注意： 只返回第一个字段的值</p>
     *
     * @param queryWrapper 实体对象封装操作类（可以为 null）
     */
    default Optional<List<Object>> listObjs(Wrapper<T> queryWrapper) {
        List<Object> objects = selectObjs(queryWrapper);
        return CollUtil.isEmpty(objects) ? Optional.empty() : Optional.of(objects);
    }


    // ======================================= 分页 ========================================

    /**
     * 分页
     *
     * @param pageParam    分页参数 需继承PageParam
     * @param queryWrapper queryWrapper
     */
    default PageResult<T> selectPage(PageParam pageParam, @Param("ew") Wrapper<T> queryWrapper) {
        // MyBatis Plus 查询
        IPage<T> mpPage = MyBatisUtils.buildPage(pageParam);
        selectPage(mpPage, queryWrapper);
        // 转换返回
        return new PageResult<>(mpPage.getRecords(), mpPage.getTotal(), mpPage.getPages(), mpPage.getCurrent(), mpPage.getSize());
    }

    /**
     * 根据 entity 条件，查询全部记录（并翻页）
     *
     * @param sortingFields 排序字段
     * @param pageParam     分页查询条件
     * @param queryWrapper  实体对象封装操作类（可以为 null）
     */
    default PageResult<T> selectPage(PageParam pageParam, @Param("ew") Wrapper<T> queryWrapper, Collection<SortingField> sortingFields) {
        // MyBatis Plus 查询
        IPage<T> mpPage = MyBatisUtils.buildPage(pageParam, sortingFields);
        selectPage(mpPage, queryWrapper);
        // 转换返回
        return new PageResult<>(mpPage.getRecords(), mpPage.getTotal(), mpPage.getPages(), mpPage.getCurrent(), mpPage.getSize());
    }
}
```

最后，在`dao`层，继承从`BaseMapper`换成`OptionalBaseMapper`即可。
