Mybatis-Plus 简介

什么是 MyBatis-Plus?Mybatis-Plus:为简化开发而生

MyBatis-Plus(简称 MP)是一个基于 MyBatis 的增强工具,它对 Mybatis 的基础功能进行了增强,但未做任何改变。使得我们可以可以在 Mybatis 开发的项目上直接进行升级为 Mybatis-plus,正如它对自己的定位,它能够帮助我们进一步简化开发过程,提高开发效率。

Mybatis-Plus 其实可以看作是对 Mybatis 的再一次封装,升级之后,对于单表的 CRUD 操作,调用 Mybatis-Plus 所提供的 API 就能够轻松实现,此外还提供了各种查询方式、分页等行为。最最重要的,开发人员还不用去编写 XML,这就大大降低了开发难度

官网:https://mp.baomidou.com

连表?Left Join?Inner Join?

MybtaisPlus 极大简便了单表的操作,但对应连表查询更多的还是在xml中实现,本人是一个单表主义者(能单表,尽量不连表),阿里的相关规范中也提到:尽量使用单表,连表尽量不要超过3张,于是更多的时候,是把主表查询处理,然后使用流处理把关联的表Id集合起来,再通过listByIds转toMap,得到Id对应的对象,再进行get相对应赋值,最初也没啥,当写的越来越多了之后,问题就开始暴露了,没错,代码实在是太长,太臭啦!!!

旧版代码

Set<Long> systemProjectFileSecurityIdSet = records.stream().map(SystemProjectFileSecurityGroupSetting::getSystemProjectFileSecurityId).collect(Collectors.toSet());
Map<Long, SystemProjectFileSecurity> systemProjectFileSecurityMap = new HashMap<>();
if (!systemProjectFileSecurityIdSet.isEmpty()) {
            systemProjectFileSecurityMap.putAll(systemProjectFileSecurityService.listByIds(systemProjectFileSecurityIdSet)
                    .stream()
                    .collect(Collectors.toMap(SystemProjectFileSecurity::getSystemProjectFileSecurityId, systemProjectFileSecurity -> systemProjectFileSecurity)));
}

旧版代码太长了啦,每次关联,都需要5-7行,一张业务表少说也有3到5个表关联,这样编写的话,显得代码太过累赘,以及冗余,整体看的实在太难受啦

新版优化

//如果你当前的数据里面有 明确目标表 的id,那请用 linkXxx;(你有目标表的id)
Map<Long, SystemProjectFileSecurity> systemProjectFileSecurityMap = 
    linkTableUtils.linkSystemProjectFileSecurity(records, SystemProjectFileSecurityGroupSetting::getSystemProjectFileSecurityId);
//如果你只有你自己的id,目标表存储你的id,那请用 xxxLink;(目标表有你id)
Map<Long, ModelProjectStaffing> map = 
    linkTableUtils.modelProjectStaffingLink(ModelProjectStaffing::getProjectId, projectList, Project::getProjectId,Collectors.toMap(ModelProjectStaffing::getProjectId, data->data));

我们对冗余的代码进行的抽取,目前1-2行就可以实现5-7行的功能,就算关联查询更多的表,代码看起来也更整洁,嗯,真香

相关工具类

import com.baomidou.mybatisplus.extension.service.IService;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 链接其他表的工具类
 * 情景一:如果你当前的数据里面有 明确目标表 的id,那请用 linkXxx;(你有目标表的id)
 * linkXxx 执行效果类似  select * from targetTable where targetTable.id in (xxx,xxx,xxx)
 * 情景二:如果你只有你自己的id,目标表存储你的id,那请用 xxxLink;(目标表有你id)
 * xxxLink 执行效果类似  select * from targetTable where targetTable.otherTableId in (xxx,xxx,xxx)
 *
 * @author zengqinghua
 */
@Component
public class LinkTableUtils {

    /**
     * 链接 XXX表
     */
    public <T> Map<Long, SystemProjectFileSecurity> linkSystemProjectFileSecurity(List<T> records, Function<T, Long> getKey) {
        return this.linkTable(TableEnum.SystemProjectFileSecurity, records, getKey, SystemProjectFileSecurity::getSystemProjectFileSecurityId);
    }


    /**
     * xxx表 链接
     */
    public <T, R> R modelProjectStaffingLink(SFunction<ModelProjectStaffing, Long> targetKey, List<T> records, Function<T, Long> sourceKey, Collector<ModelProjectStaffing, ?, R> collector) {
        return this.tableLink(TableEnum.ModelProjectStaffing, targetKey, records, sourceKey, collector);
    }

    /**
     * 链接 表(通用方法)
     *
     * @param tableEnum 表名枚举
     * @param records   数据源列表
     * @param getKey    查询的Id
     * @param getRKey   map的key
     * @param <T>       数据源泛型
     * @param <R>       目标结果泛型
     * @return
     */
    public <T, R> Map<Long, R> linkTable(
            TableEnum tableEnum,
            List<T> records, Function<T, Long> getKey,
            Function<R, Long> getRKey
    ) {
        if (records.isEmpty()) {
            return new HashMap<>();
        }

        // 得到对应的id
        Set<Long> idSet = records.stream().map(getKey).collect(Collectors.toSet());
        if (idSet.isEmpty()) {
            return new HashMap<>();
        }

        IService<R> iService = (IService) ApplicationContextUtil.getBean(tableEnum.tClass);
        return iService.listByIds(idSet)
                .stream()
                .collect(Collectors.toMap(getRKey, data -> data));
    }

    /**
     * 链接 表(通用方法)
     *
     * @param tableEnum         表名枚举
     * @param targetSearchField 目标查询的字段
     * @param records           数据源列表
     * @param sourceField       数据源字段
     * @param <T>               数据源泛型
     * @param <T2>              目标泛型
     * @param <R>               结果泛型
     * @return
     */
    public <T, T2, R> R tableLink(
            TableEnum tableEnum,
            SFunction<T2, Long> targetSearchField,
            List<T> records, Function<T, Long> sourceField,
            Collector<T2, ?, R> collector
    ) {
        if (records.isEmpty()) {
            return (R) collector.supplier().get();
        }

        // 得到对应的id
        Set<Long> idSet = records.stream().map(sourceField).collect(Collectors.toSet());
        if (idSet.isEmpty()) {
            return (R) collector.supplier().get();
        }

        IService<T2> iService = (IService) ApplicationContextUtil.getBean(tableEnum.tClass);
        return iService.list(Wrappers.<T2>lambdaQuery()
                .in(targetSearchField, idSet))
                .stream()
                .collect(collector);
    }

    public enum TableEnum {
        SystemProjectFileSecurity("xxxx", ISystemProjectFileSecurityService.class),
        ModelProjectStaffing("xxx", IModelProjectStaffingService.class),
        ;

        private final String tableRemark;
        private final Class tClass;

        TableEnum(String tableRemark, Class tClass) {
            this.tableRemark = tableRemark;
            this.tClass = tClass;
        }
    }
}
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

@Component
@Lazy(false)
public class ApplicationContextUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext = null;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (ApplicationContextUtil.applicationContext == null) {
            ApplicationContextUtil.applicationContext = applicationContext;
        }
    }

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    public static <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }

    /**
     * 根据bean名称获取指定类型bean
     *
     * @param beanName bean名称
     * @param clazz    返回的bean类型,若类型不匹配,将抛出异常
     */
    public static <T> T getBean(String beanName, Class<T> clazz) {
        return getApplicationContext().getBean(beanName, clazz);
    }
}

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐