介绍
MappedStatement类在Mybatis框架中用于表示XML文件中一个sql语句节点,即一个、或者标签。Mybatis框架在初始化阶段会对XML配置文件进行读取,将其中的sql语句节点对象化为一个个MappedStatement对象。
若是使用注解,则类似注解中的@Select等描述。
public final class MappedStatement {
//节点中的id属性加要命名空间
private String id;
//直接从节点属性中取
private Integer fetchSize;
//直接从节点属性中取
private Integer timeout;
private StatementType statementType;
private ResultSetType resultSetType;
//对应一条SQL语句
private SqlSource sqlSource;
//每条语句都对就一个缓存,如果有的话。
private Cache cache;
//这个已经过时了
private ParameterMap parameterMap;
private List<ResultMap> resultMaps;
private boolean flushCacheRequired;
private boolean useCache;
private boolean resultOrdered;
//SQL的类型,select/update/insert/detete
private SqlCommandType sqlCommandType;
private KeyGenerator keyGenerator;
private String[] keyProperties;
private String[] keyColumns;
//是否有内映射
private boolean hasNestedResultMaps;
private String databaseId;
private Log statementLog;
private LanguageDriver lang;
private String[] resultSets;
在Mybatis框架中用于表示XML文件中一个sql语句节点,即一个、或者标签。即一个sql语句对应一个MappedStatment对象。
创建
和Configration一样,是在构建SqlSesstionFactory的时候创建的。对象由Configration持有。
new SqlSessionFactoryBuilder().build(inputStream);
调用
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(());//()这里调用
。。。
}
----------
private void parseConfiguration(XNode root) {
...
mapperElement(("mappers"));
...
}
private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : ()) {
if ("package".equals(())) {
String mapperPackage = ("name");
(mapperPackage);
} else {
String resource = ("resource");
String url = ("url");
String mapperClass = ("class");
if (resource != null && url == null && mapperClass == null) {
().resource(resource);
InputStream inputStream = (resource);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, ());
();
...
-------
public void parse() {
if (!(resource)) {
configurationElement(("/mapper"));
...
}
...
}
private void configurationElement(XNode context) {
try {
...
buildStatementFromContext(("select|insert|update|delete"));
} catch (Exception e) {
throw new BuilderException("Error parsing Mapper XML. Cause: " + e, e);
}
}
private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
for (XNode context : list) {
final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
try {
();//遍历解析<inser> update 等节点
} catch (IncompleteElementException e) {
(statementParser);
}
}
}
public void parseStatementNode() {
...
(id, sqlSource, statementType, sqlCommandType,
fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
resultSetTypeEnum, flushCache, useCache, resultOrdered,
keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}
到这里可以知道MappedStatement是在MapperBuilderAssistant中创建的。
-------
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 == ;
statementBuilder = new (configuration, id, sqlSource, sqlCommandType);
(resource);
(fetchSize);
(statementType);
(keyGenerator);
(keyProperty);
(keyColumn);
(databaseId);
(lang);
(resultOrdered);
(resultSets);
setStatementTimeout(timeout, statementBuilder);
setStatementParameterMap(parameterMap, parameterType, statementBuilder);
setStatementResultMap(resultMap, resultType, resultSetType, statementBuilder);
setStatementCache(isSelect, flushCache, useCache, currentCache, statementBuilder);
MappedStatement statement = ();
(statement);
return statement;
}
-----
public void addMappedStatement(MappedStatement ms) {
((), ms);
}
从上面代码可以看到。在解析Insert等节点的时候创建的MappedStaement,在MapperBuilderAssistant中创建。创建完成之后保存在Configration的map中。
StrictMap
MappedStatement使用的map是在Configration中定义的
StrictMap(主要关注put和map):
protected static class StrictMap<V> extends HashMap<String, V> {
public V put(String key, V value) {
if (this.containsKey(key)) {
throw new IllegalArgumentException(this.name + " already contains value for " + key);
} else {
if ((".")) {
String shortKey = this.getShortName(key);
if (super.get(shortKey) == null) {
(shortKey, value);
} else {
(shortKey, new (shortKey));
}
}
return (key, value);
}
}
public V get(Object key) {
V value = super.get(key);
if (value == null) {
throw new IllegalArgumentException(this.name + " does not contain value for " + key);
} else if (value instanceof ) {
throw new IllegalArgumentException((()value).getSubject() + " is ambiguous in " + this.name + " (try using the full name including the namespace, or rename one of the entries)");
} else {
return value;
}
}
private String getShortName(String key) {
String[] keyParts = ("\\.");
return keyParts[ - 1];
}
可以看到在put的时候会对key进行判重。即我们在xml或者注解中定义的这组合id必须是唯一的。
获取
根据节点中的id属性加要命名空间来获取
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
MappedStatement ms = (statement);
List<E> result = (ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
return result;
} catch (Exception e) {
throw ("Error querying database. Cause: " + e, e);
} finally {
().reset();
}
}
从这里看出通过调用Configration的 MappedStatement ms = (statement)来获取对应的MappedStaement。