mybatis-plus从入门到入土(四):持久层接口之BaseMapper和选装件
大家好,今天继续更新MybatisPlus从入门到入土系列,上一次的持久层接口还没讲完,只讲了IService接口,今天我们继续来讲一下。
BaseMapper
BaseMapper中的方法也比较简单,都是增删改查的基础API,不知道大家还有没有印象,上次在讲IService相关类结构的时候,我们分析了一个CrudRepository,它就是通过成员变量BaseMapper完成了部门能力,当时我还把BaseMapper比喻成引擎(或者发动机)。BaseMapper的相关类结构只有一个父接口Mapper,Mapper接口作为顶层接口,只起到标记的作用,没有定义方法。因此BaseMapper的相关类结构是非常清晰的,这里也不过多赘述了。关于BaseMapper的实现原理,我们计划在后面讲解源码的时候会讲到。
Mapper层选装件
关于Mapper层选装件,其实就是Mapper的扩展功能,虽然MybatisPlus已经提供了BaseMapper这个比较丰富的父类,但是还是有些比较场景化的需求需要定制实现,这就是选装件的意义。在官方文档中描述也可以看出,选装件是需要配合SQL注入器一起使用的。关于SQL注入器后面还会单独说到,这些选装件都位于com.baomidou.mybatisplus.extension.injector.methods,下面我们具体来看下这几个选装件。

关于这几个选装件的作用,大家可以看下官方文档https://baomidou.com/guides/data-interface/#mapper-%E5%B1%82%E9%80%89%E8%A3%85%E4%BB%B6,我们主要分析下他们的具体实现。还有一点需要补充的是,关于SQL注入器后面会讲到,今天只对这几个选装件做一下剖析。
首先在3.5.12版本中能看到的选装件有5个:AlwaysUpdateSomeColumnById、InsertBatchSomeColumn、LogicDeleteBatchByIds、LogicDeleteByIdWithFill,Upsert。其中LogicDeleteBatchByIds和LogicDeleteByIdWithFill官方已标注为过期。
AbstractMethod
首先说下他们都继承的类,就是这个AbstractMethod,AbstractMethod作为SQL注入的基础类,它的主要方法是inject方法。
TIPS
这里说一个小技巧啊,当你看源码的时候,仅从类出发不知道入口点是哪个方法,可以先找下类中public的方法,一般需要子类实现的都会标注为protected。
/*** 注入自定义方法*/
public void inject(MapperBuilderAssistant builderAssistant, Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {this.configuration = builderAssistant.getConfiguration();this.builderAssistant = builderAssistant;this.languageDriver = configuration.getDefaultScriptingLanguageInstance();/* 注入自定义方法 */injectMappedStatement(mapperClass, modelClass, tableInfo);
}
再看下injectMappedStatement方法。injectMappedStatement是一个抽象方法,实现的子类就包括我们提到的那几个选装件。

我们挑一个看下吧,比如AlwaysUpdateSomeColumnById,看下这个类中的injectMappedStatement是怎么实现的。
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {SqlMethod sqlMethod = SqlMethod.UPDATE_BY_ID;final String additional = optlockVersion(tableInfo) + tableInfo.getLogicDeleteSql(true, true);String sqlSet = this.filterTableFieldInfo(tableInfo.getFieldList(), getPredicate(),i -> i.getSqlSet(true, ENTITY_DOT), NEWLINE);sqlSet = SqlScriptUtils.convertSet(sqlSet);String sql = String.format(sqlMethod.getSql(), tableInfo.getTableName(), sqlSet,tableInfo.getKeyColumn(), ENTITY_DOT + tableInfo.getKeyProperty(), additional);SqlSource sqlSource = super.createSqlSource(configuration, sql, modelClass);return addUpdateMappedStatement(mapperClass, modelClass, methodName, sqlSource);
}
这个方法的主要作用就是创建一个update的MappeedStatement,加入到Mybatis的全局配置中。其中sqlMethod是SQL语句的模板,拿到这个UPDATE_BY_ID的sql语句模板后,下面就是把模板填充成正常的SQL语句,就涉及到需要set的字段啊,乐观锁之类的。当这些信息都拼接完了,把它放入一个SqlSource的对象中,然后根据这个SqlSource对象生成MappedStatement。整个方法逻辑看起来比较清晰,但是有几点需要补充一下,如果没有这些前置知识,这块可能还是比较蒙。
-
SqlMethod长什么样?
我们看下这个SqlMethod究竟长什么样,其实就是一个
String模板,也就是我们经常用的String.format的定义形式。而<script>标签是Mybatis提供的,该标签主要是用来拼接SQL脚本的。UPDATE_BY_ID("updateById", "根据ID 选择修改数据", "<script>\nUPDATE %s %s WHERE %s=#{%s} %s\n</script>") -
MappedStatement类是干什么的?
这个类是
Mybatis框架中的重要类,他对应的就是xml文件中的一个个标签包起来的元素,比如<insert>元素,<select>元素。这里简述一下Mybatis的原理啊,Mybatis框架启动的时候会去解析xml文件,将里面的一个个标签实例化成一个个MappedStatement对象。最终这些解析出来的MappedStatement都会放入Configuration类,关于这一块大家可以看下org.apache.ibatis.builder.xml.XMLConfigBuilder#parseConfiguration。 -
SqlSource类是干什么的?
其实从类的注释中,我们基本上也能明白是什么意思了,就是在
<insert>标签中的插入语句,包在<select>语句中的查询语句等,这个SqlSource类的作用就是这些SQL语句的容器。/*** Represents the content of a mapped statement read from an XML file or an annotation. It creates the SQL that will be passed to the database out of the input parameter received from the user.* 表示从 XML 文件或注释读取的映射语句的内容。它创建将从用户收到的输入参数传递到数据库的 SQL。* @author Clinton Begin*/ public interface SqlSource {BoundSql getBoundSql(Object parameterObject);}
经过上面的几个问题,大家应该知道了这几个类其实就是定义了几个不同的MappedStatement方法,然后注入到Configuration类中。相比于传统的在xml中定义,或者在mapper方法上面注解定义,这些都是自己注入的,关于怎么注入的,在哪注入的,这块就是SQL注入器的内容了,我们后面会讲到。
好了,今天先讲到这里。这里需要说明一下,官方文档中持久化接口涉及的东西很多,我们可能得分多次讲解,我最初规划的是一篇讲完的,但我还是觉得一次讲太多会很长,也不太好消化,就篇幅短一些吧。下周见,拜拜。
先讲到这里。这里需要说明一下,官方文档中持久化接口涉及的东西很多,我们可能得分多次讲解,我最初规划的是一篇讲完的,但我还是觉得一次讲太多会很长,也不太好消化,就篇幅短一些吧。下周见,拜拜。
