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注入器的内容了,我们后面会讲到。
好了,今天先讲到这里。这里需要说明一下,官方文档中持久化接口涉及的东西很多,我们可能得分多次讲解,我最初规划的是一篇讲完的,但我还是觉得一次讲太多会很长,也不太好消化,就篇幅短一些吧。下周见,拜拜。
先讲到这里。这里需要说明一下,官方文档中持久化接口涉及的东西很多,我们可能得分多次讲解,我最初规划的是一篇讲完的,但我还是觉得一次讲太多会很长,也不太好消化,就篇幅短一些吧。下周见,拜拜。