越来越多的人在使用Mybatis-plus。基本上不需要写代码就可以完成单表的增删改查。使用时我们只需要从原来的Mapper接口文件继承BaseMapper即可自动完成单表的CRUD。之前一直在用,从来没有想过如何实现。经过一下午的时间,我大致了解了Mybatis-plus是如何实现通用单表CRUD的。
在讲原理之前,我们先简单了解一下Mybatis是如何实现查询的。示例代码如下:
@Slf4j
public class MybatisApp {
公共 静态 void main(字符串[] args) 投掷 IOException {
字符串资源 = "mybatis-config. xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory 工厂= new SqlSessionFactoryBuilder().build(inputStream);
尝试 (SqlSession session = factory.openSession()) {
UserEntity user = (UserEntity) www.gsm-guard.netOne("com.buydeem.mapper.UserMapper.getById", 1);
www.gsm-guard.net("{}",用户);
}
}
}
配置
PUBLIC "-//www.gsm-guard.net//DTD Config 3.0/ /CN"
"https:// www.gsm-guard.net/dtd/mybatis-3-config.dtd">
<配置>
< 属性 资源="jdbc.properties">
属性>
<设置>
<设置 名称="mapUnderscoreToCamelCase" 值=“真”/>
设置>
<类型别名>
<包装 名称="com.buydeem.entity"/>
类型别名>
<环境 默认 =“开发”>
<环境 id=“发展”>
< transactionManager 类型="JDBC"/>
<数据源类型="POOLED">
<属性 名称=“驱动程序” 值="${jdbc.driver}"/>
<属性 名称="url" 值="${jdbc.url}"/>
<属性 姓名="用户名" 值="${jdbc.用户名}"/>
<属性 名称= "密码" 值="${jdbc.password}"/>
数据源>
环境>
环境>
<映射器>
< 映射器 资源="mapper/UserMapper.xml"/>
映射器>
< /配置>
映射器
PUBLIC"-//www.gsm-guard.net//DTD映射器3.0//EN"
》https: // www.gsm-guard.net/dtd/mybatis-3-mapper.dtd">
<mapper 命名空间= “com.buydeem.mapper.UserMapper ” | “getById”结果类型=“用户实体”? 映射器>
示例代码很简单,首先通过读取配置文件创建一个SqlSessionFactory
,然后获取SqlSession
来执行查询。
通过前面简单的例子,似乎还是不清楚原因。我们先看一下www.gsm-guard.netOne()
的实现并跟踪它的源代码。最终实现如下:
私人 列表 选择列表(字符串语句、对象参数、RowBounds rowBounds、ResultHandler 处理程序) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
return executor.query(ms, wrapCollection(参数), rowBounds, 处理程序);
} catch (异常 e) {
抛出 ExceptionFactory.wrapException("错误正在查询数据库。原因:“ + e, e);
} 最后 {
ErrorContext.instance().reset();
}
}
该方法从配置
中获取一个MappedStatement
实例,然后将其关联执行器 去执行。
首先我们要分析一下这个配置
是个什么东西。在我们的示例代码中,它实际上就是读取mybatis-config.xml
配置文件构建出一个配置类。从Configuration
的源码中也有体现,这个配置类中的属性与mybatis-config.xml
能够回复起来。
MappedStatement ms = 配置.getMappedStatement(语句
该代码是从MappedStatement
实例的Configuration
实例中获取,其内部实现如下:
public MappedStatement getMappedStatement(字符串 id,布尔值 验证日期不完整的陈述) {
if ( validateIncompleteStatements } }
实际上是从 Configuration 中的属性
mappedStatements
获取 MappedStatement
示例。
受保护 最终映射映射语句 = 新 StrictMap("映射语句集合")
.conflictMessageProducer((savedValue, targetValue) ->
”。请检查“ + savingValue.getResource() + ”和“” + targetValue.getResource());
您可以看到Configuration
中的mappedStatements
类型为StrictMap ,它继承了HashMap,并重写了put和get方法。
public V put(字符串键,V值) {
if(包含Key(键)){
抛出 new IllegalArgumentException(名称 + ”已包含“ + 键
+ 的值(conflictMessageProducer == null? "" : conflictMessageProducer.apply(super.get(key), value)));
} if(key.contains( ".")) {
final String shortKey = getShortName(key);
if (超级.get (shortKey) == null) {
super.put(shortKey, 值);
} 否则 {
super.put(shortKey, (V) new 歧义(shortKey));
}
} 回归 超级 .put(key, value);
}
公共 V 获取(对象键) {
V值=super.get(key);
if (value == null) { 扔 新 IllegalArgumentException(名称+”不包含“+键)的值;
}
if (值实例含糊不清){
throw new IllegalArgumentException(((Ambiguity) value).getSubject() + " 在“”中不明确 + 姓名
+ ”(尝试使用包含命名空间的全名,或重命名其中一个条目)");
}
return值;
}
通过前面我们了解到配置
内部用一个Map来存储MappedStatement
,现在的问题是它什么时候被撤去的。
public void addMappedStatement(MappedStatement ms) {
mappedStatements.put(ms.getId(), ms) ;
}
在配置
中,仅提供了一种方法来添加MappedStatement
。同时还可以了解一点配置
存储MappedStatement
Map的key是MappedStatement的ID属性。唯一调用
Configuration.addMappedStatement()
方法的是 MapperBuilderAssistant
。从名字就可以看出,这个类是用来构建Mapper的工具类。我们创建的Mapper.xml文件中的sql语句其实就是解析xml文件,然后通过这个工具类将其转换为MappedStatement
并存储在Configuration
实例中。本文不会详细介绍如何解析xml。如果有兴趣可以自己阅读源码。
现在的问题是这个MappedStatement
有什么用?
public final class MappedStatement {
私有 字符串资源;
private 配置配置;
private 字符串id;
private 整数 fetchSize;
private 整数超时;
private StatementType statementType;
privateResultSetType resultSetType;
私有 SqlSource sqlSource;
私有 缓存缓存;
private ParameterMap parameterMap;
private 列表结果地图;
private booleanflushCacheRequired;
私有 booleanuseCache;
私有 boolean结果已排序;
privateSqlCommandType sqlCommandType;
私有 密钥生成器 keyGenerator;
私有字符串[] keyProperties;
private String[] keyColumns;
private boolean hasNestedResultMaps;
private String databaseId;
private 日志语句Log;
private LanguageDriver lang; private String[] resultSets;
}
其实每一个MappedStatement
都对应着我们自定义的Mapper接口中的一个方法,它保存了我们定义的SQL语句的配置、参数结构、返回值结构、Mybatis的处理方式等。内容对应于我们的Mapper.xml 中定义的内容。