我们知道一个MappedStatement对象表示的是XML中的一个SQL信息,主要属性如下。
public final class MappedStatement {
//sql的ID,mapper接口的方法名
private String id;
//SQL超时时间
private Integer timeout;
//Statement的类型,STATEMENT/PREPARE/CALLABLE,默认PREPARE
private StatementType statementType;
//结果集类型,FORWARD_ONLY/SCROLL_SENSITIVE/SCROLL_INSENSITIVE
private ResultSetType resultSetType;
//表示解析出来的SQL
private SqlSource sqlSource;
//缓存,查询用
private Cache cache;
//对应的ResultMap
private List<ResultMap> resultMaps;
// 是否刷新缓存
private boolean flushCacheRequired;
// 是否使用二级缓存,一级缓存是session的
private boolean useCache;
//SQL类型,select|insert|update|delete"
private SqlCommandType sqlCommandType;
//数据库ID
private String databaseId;
}
Mybatis 通过解析 XML,生成 sql 对应的 MappedStatement ,并放入 SqlSessionTemplate 中 configuration 类属性中,等正真执行 mapper 接口中的方法时,根据mapper接口的全类名+方法名作为key,会从 configuration 中找到对应的 mappedStatement ,然后进行后续的操作。
本文以mybatisplus为例,大体涉及到的类有MybatisPlusAutoConfiguration、MybatisSqlSessionFactoryBean、XMLMapperBuilder、MapperBuilderAssistant
MybatisPlusAutoConfiguration.java
首先加入mybatisplus的依赖后,sping boot找到com.baodidou.mybatisplus.autoconfigure包下面的META-INF/spring.factory,根据自动装配去加载MybatisPlusAutoConfiguration里面的属性,
@Configuration
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties({MybatisPlusProperties.class})
@AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisPlusLanguageDriverAutoConfiguration.class})
public class MybatisPlusAutoConfiguration implements InitializingBean {
// 初始化SqlSessionFactory,MappedStatement生成的入口
@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
return factory.getObject();
}
}
MybatisSqlSessionFactoryBean.java
调用MybatisSqlSessionFactoryBean里面的getObject(),进而调用this.afterPropertiesSet(),然后调用buildSqlSessionFactory()
public class MybatisSqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
public SqlSessionFactory getObject() throws Exception {
if (this.sqlSessionFactory == null) {
this.afterPropertiesSet();
}
return this.sqlSessionFactory;
}
@Override
public void afterPropertiesSet() throws Exception {
this.sqlSessionFactory = buildSqlSessionFactory();
}
protected SqlSessionFactory buildSqlSessionFactory() throws Exception {
// this.mapperLocations 项目配置的所有mybatis xml文件 比如: 项目路径\target\classes\mapper\SelectUserMapper.xml
if (this.mapperLocations != null) {
for (Resource mapperLocation : this.mapperLocations) {
// 解析xml
xmlMapperBuilder.parse();
}
}
}
}
XMLMapperBuilder.java
调用XMLMapperBuilder的parse(),关键方法?configurationElement(parser.evalNode("/mapper"));
public class XMLMapperBuilder extends BaseBuilder {
public void parse() {
if (!configuration.isResourceLoaded(resource)) {
//从mapper根节点开始解析
configurationElement(parser.evalNode("/mapper"));
}
private void configurationElement(XNode context) {
//解析mapper的namespace
String namespace = context.getStringAttribute("namespace");
//解析resultMap节点
resultMapElements(context.evalNodes("/mapper/resultMap"));
//解析SQL语句(select|insert|update|delete节点)
buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
}
private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
//遍历XNode
for (XNode context : list) {
try {
//解析StatementNode
statementParser.parseStatementNode();
} catch (IncompleteElementException e) {
//解析报错的,在parsePendingStatements方法中再解析
configuration.addIncompleteStatement(statementParser);
}
}
}
public void parseStatementNode() {
//获取sql标签的id
String id = context.getStringAttribute("id");
// 获取sql的类型,select|insert|update|delete
String nodeName = context.getNode().getNodeName();
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
// 是否刷新缓存,默认查询不刷新
boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect);
// 是否对该语句进行二级缓存; select 默认为 true。
boolean useCache = context.getBooleanAttribute("useCache", isSelect);
SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
// statementType 未设置默认PREPARED
StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
// 参数
String parameterMap = context.getStringAttribute("parameterMap");
// 返回值类型
String resultType = context.getStringAttribute("resultType");
/通过buildAssistant将解析得到的参数设置构造成MappedStatement对象
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
resultSetTypeEnum, flushCache, useCache, resultOrdered,
keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}
}
MapperBuilderAssistant.java
最后调用MapperBuilderAssistant的addMappedStatement方法完成向configuration添加MappedStatement
public class MapperBuilderAssistant extends BaseBuilder {
public MappedStatement addMappedStatement(
String id,
SqlSource sqlSource,
StatementType statementType,
SqlCommandType sqlCommandType,
Integer fetchSize,
Integer timeout,
String parameterMap,
Class<?> parameterType,
String resultMap,
Class<?> resultType,
ResultSetType resultSetType,
boolean flushCache,
boolean useCache,
boolean resultOrdered,
KeyGenerator keyGenerator,
String keyProperty,
String keyColumn,
String databaseId,
LanguageDriver lang,
String resultSets) {
if (unresolvedCacheRef) {
throw new IncompleteElementException("Cache-ref not yet resolved");
}
id = applyCurrentNamespace(id, false);
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
//构造MappedStatement
MappedStatement.Builder statementBuilder = new MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType)
.resource(resource)
.fetchSize(fetchSize)
.timeout(timeout)
.statementType(statementType)
.keyGenerator(keyGenerator)
.keyProperty(keyProperty)
.keyColumn(keyColumn)
.databaseId(databaseId)
.lang(lang)
.resultOrdered(resultOrdered)
.resultSets(resultSets)
.resultMaps(getStatementResultMaps(resultMap, resultType, id))
.resultSetType(resultSetType)
.flushCacheRequired(valueOrDefault(flushCache, !isSelect))
.useCache(valueOrDefault(useCache, isSelect))
.cache(currentCache);
ParameterMap statementParameterMap = getStatementParameterMap(parameterMap, parameterType, id);
if (statementParameterMap != null) {
statementBuilder.parameterMap(statementParameterMap);
}
MappedStatement statement = statementBuilder.build();
// 向configuration添加MappedStatement
configuration.addMappedStatement(statement);
return statement;
}
}
总体流程
1:spring boot 启动,加载MybatisPlusAutoConfiguration.java类,初始化SqlSessionFactory,
2:MybatisSqlSessionFactoryBean调用MybatisSqlSessionFactoryBean.java的getObject()方法,进而调用this.afterPropertiesSet()方法
3:调用buildSqlSessionFactory()方法获取项目配置的所有mybatis xml文件,通过xmlMapperBuilder.parse()方法循环解析xml
4:调用buildStatementFromContext(context.evalNodes("select|insert|update|delete"))方法解析sql节点
5:调用parseStatementNode() 方法获取xml里面的具体sql信息
6:调用builderAssistant.addMappedStatement方法进行封装MappedStatement对象,最后调用configuration.addMappedStatement(statement)放入到configuration里
|