1.前言
mybatis用作数据库操作的中间件,相信大家都不会陌生,那么我们今天就从源码角度来说说mybatis的原理,看看它是怎么根据我们定义好的配置操作数据库,首先我们看一下mybatis的使用方式。
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
LiveCourseMapper mapper = sqlSession.getMapper(UserMapper.class);
List<LiveCourse> userList = mapper.getUserList();
这里我们只能猜出个一二,即通过配置文件构造SqlSession,通过SqlSession操作数据库
2.框架流程图


3.源码解析
3.1、Mapper解析
XMLMapperBuilder的configurationElement方法用来解析mapper,这里协助的类有MapperBuilderAssistant、CacheRefResolver、ResultMapResolver,个人觉得这里的Resolver完全是多次一举,Resolver最后还是通过MapperBuilderAssistant实现
private void configurationElement(XNode context) {
try {
//解析namespace属性
String namespace = context.getStringAttribute("namespace");
if (namespace.equals("")) {
throw new BuilderException("Mapper's namespace cannot be empty");
}
//设置命名空间
builderAssistant.setCurrentNamespace(namespace);
//将此命名空间关联namespace属性指定的命名空间,并设置为当前cache
cacheRefElement(context.evalNode("cache-ref"));
//构造cache添加到configuration,并设置为当前cache
cacheElement(context.evalNode("cache"));
//构造ParameterMap添加到configuration
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
//构造ResultMap添加到configuration
resultMapElements(context.evalNodes("/mapper/resultMap"));
//识别sql并缓存,缓存id带有命名空间
sqlElement(context.evalNodes("/mapper/sql"));
//构造MappedStatement添加到configuration
buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
} catch (Exception e) {
throw new BuilderException("Error parsing Mapper XML. Cause: " + e, e);
}
}
MapperBuilderAssistant是XMLMapperBuilder解析的协助类,一般是XMLMapperBuilder读取各个节点的属性和子节点,然后通过MapperBuilderAssistant创建不同的对象
public class MapperBuilderAssistant extends BaseBuilder {
//当前命名空间,mapper标签的namespace属性
private String currentNamespace;
//资源路径
private String resource;
//当前缓存
private Cache currentCache;
//缓存引用解决标志,解析cache-ref使用
private boolean unresolvedCacheRef;
//获取namespace对应的cache设置到currentCache,解析cache-ref使用
public Cache useCacheRef(String namespace)
//构造cache设置到currentCache并添加到configuration,解析cache使用
public Cache useNewCache()
//构造ParameterMap并添加到configuration,使用build模式,解析parameterMap使用
public ParameterMap addParameterMap()
//构造ParameterMapping,使用build模式,解析parameterMap使用
public ParameterMapping buildParameterMapping()
//构造ResultMap并添加到configuration,使用build模式,解析resultMap使用
public ResultMap addResultMap()
//构造Discriminator,使用build模式,解析resultMap使用
public Discriminator buildDiscriminator()
//构造ResultMapping,使用build模式,解析resultMap使用
public ResultMapping buildResultMapping()
//构造MappedStatement并添加到configuration,使用build模式,解析select|insert|update|delete使用
public MappedStatement addMappedStatement()
//设置MappedStatement.Builder的cache,解析select|insert|update|delete使用
private void setStatementCache()
//设置MappedStatement.Builder的parameterMap,解析select|insert|update|delete使用
private void setStatementParameterMap()
//设置MappedStatement.Builder的resultMaps(多个)和resultSetType,解析select|insert|update|delete使用
private void setStatementResultMap()
//设置MappedStatement.Builder的timeout,解析select|insert|update|delete使用
private void setStatementTimeout()
//解决result的java类型
private Class<?> resolveResultJavaType()
//解决parameter的java类型
private Class<?> resolveParameterJavaType()
}
XMLMapperBuilder解析select|insert|update|delete节点时,由于解析过于复杂,这里解析属性和子节点是通过XMLStatementBuilder来实现
public class XMLStatementBuilder extends BaseBuilder {
//mapper解析助手
private MapperBuilderAssistant builderAssistant;
//当前节点
private XNode context;
//配置的databaseId
private String requiredDatabaseId;
//
public void parseStatementNode
public void parseStatementNode() {
//获取当前节点上的属性
Integer fetchSize = context.getIntAttribute("fetchSize");
Integer timeout = context.getIntAttribute("timeout");
String parameterMap = context.getStringAttribute("parameterMap");
String parameterType = context.getStringAttribute("parameterType");
Class<?> parameterTypeClass = resolveClass(parameterType);
String resultMap = context.getStringAttribute("resultMap");
String resultType = context.getStringAttribute("resultType");
String lang = context.getStringAttribute("lang");
LanguageDriver langDriver = getLanguageDriver(lang);
//解析resultType对应的class
Class<?> resultTypeClass = resolveClass(resultType);
String resultSetType = context.getStringAttribute("resultSetType");
StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
//解析resultSetType对应的实例
ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);
String nodeName = context.getNode().getNodeName();
SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
//非查询是否刷新缓存
boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect);
//查询是否使用缓存
boolean useCache = context.getBooleanAttribute("useCache", isSelect);
boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false);
//解析include标签,用实际sql替换include标签
XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);
includeParser.applyIncludes(context.getNode());
//解析selectKey,同时创建MappedStatement
processSelectKeyNodes(id, parameterTypeClass, langDriver);
//解析sql生成SqlSource
SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
//获取其余的属性
String resultSets = context.getStringAttribute("resultSets");
String keyProperty = context.getStringAttribute("keyProperty");
String keyColumn = context.getStringAttribute("keyColumn");
KeyGenerator keyGenerator;
String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;
keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true);
//如果定义了主键生成器则获取否则初始化主键生成器,后面学习一下KeyGenerator
if (configuration.hasKeyGenerator(keyStatementId)) {
keyGenerator = configuration.getKeyGenerator(keyStatementId);
} else {
keyGenerator = context.getBooleanAttribute("useGeneratedKeys",
configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))
? new Jdbc3KeyGenerator() : new NoKeyGenerator();
}
//构造MappedStatement并添加到configuration,使用build模式
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
resultSetTypeEnum, flushCache, useCache, resultOrdered,
keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}
}
这里解析SqlSource用了LanguageDriver,XMLLanguageDriver是LanguageDriver默认实现类,解析成SqlSource是为了获取BoundSql,SqlSource只有唯一的方法getBoundSql,BoundSql是为后面StatementHandler使用
//解析XNode生成SqlSource
public SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType) {
XMLScriptBuilder builder = new XMLScriptBuilder(configuration, script, parameterType);
return builder.parseScriptNode();
}
LanguageDriver还是通过XMLScriptBuilder实现SqlSource解析;DynamicSqlSource和RawSqlSource区别是动态sql和静态sql之分,DynamicSqlSource需要参数解析,而RawSqlSource不需要参数解析,所以DynamicSqlSource包含了SqlNode,而RawSqlSource包含了SqlSource,这里的SqlSource不是自身,而是StaticSqlSource,在后面我们会细讲
public class XMLScriptBuilder extends BaseBuilder {
//解析的XNode
private XNode context;
//是否动态sql,解析的时候初始化
private boolean isDynamic;
//参数类型
private Class<?> parameterType;
//解析XNode生成SqlSource,步骤是解析成SqlNode,然后合成MixedSqlNode,再生成SqlSource
public SqlSource parseScriptNode(){
//解析XNode生成List<SqlNode>
List<SqlNode> contents = parseDynamicTags(context);
//根据List<SqlNode>生成MixedSqlNode
MixedSqlNode rootSqlNode = new MixedSqlNode(contents);
SqlSource sqlSource = null;
if (isDynamic) {
//如果是动态sql生成DynamicSqlSource
sqlSource = new DynamicSqlSource(configuration, rootSqlNode);
} else {
//如果是静态sql生成RawSqlSource
sqlSource = new RawSqlSource(configuration, rootSqlNode, parameterType);
}
return sqlSource;
}
//解析XNode生成SqlNode
private List<SqlNode> parseDynamicTags(XNode node) {
List<SqlNode> contents = new ArrayList<SqlNode>();
NodeList children = node.getNode().getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
XNode child = node.newXNode(children.item(i));
//如果node类型是CDATA或者text
if (child.getNode().getNodeType() == Node.CDATA_SECTION_NODE || child.getNode().getNodeType() == Node.TEXT_NODE) {
String data = child.getStringBody("");
//获取CDATA或者text类型node的主体
TextSqlNode textSqlNode = new TextSqlNode(data);
//判断是否是动态sql并创建StaticTextSqlNode、TextSqlNode
if (textSqlNode.isDynamic()) {
contents.add(textSqlNode);
isDynamic = true;
} else {
contents.add(new StaticTextSqlNode(data));
}
} else if (child.getNode().getNodeType() == Node.ELEMENT_NODE) { // issue #628
//获取节点名称和节点的处理器
String nodeName = child.getNode().getNodeName();
NodeHandler handler = nodeHandlers.get(nodeName);
if (handler == null) {
throw new BuilderException("Unknown element <" + nodeName + "> in SQL statement.");
}
//使用节点处理器生成不同的SqlNode
handler.handleNode(child, contents);
isDynamic = true;
}
}
return contents;
}
//生成SqlNode
private interface NodeHandler
//生成VarDeclSqlNode
private class BindHandler implements NodeHandler
//生成TrimHandler
private class TrimHandler implements NodeHandler
//生成WhereHandler
private class WhereHandler implements NodeHandler
//生成SetSqlNode
private class SetHandler implements NodeHandler
//生成ForEachSqlNode
private class ForEachHandler implements NodeHandler
//生成IfHandler
private class IfHandler implements NodeHandler
//生成MixedSqlNode
private class OtherwiseHandler implements NodeHandler
//生成ChooseSqlNode
private class ChooseHandler implements NodeHandler
}
3.2、SQLNode解析
SqlNode是解析select|insert|update|delete后的sql对象,每个非文本节点包含了子节点SqlNode,文本节点包含sql文本,每个节点都包含了apply方法,这是运行时获取Sql使用
//TextSqlNode用来解析SQL文本节点,这里使用GenericTokenParser检测\${},DynamicCheckerTokenParser检测当前SQL文本节点是不是动态sql,BindingTokenParser找到实际值并替换
public class TextSqlNode implements SqlNode {
//sql文本
private String text;
public TextSqlNode(String text) {
this.text = text;
}
//校验是否是动态sql
public boolean isDynamic(){
//动态sql检验TokenHandler
DynamicCheckerTokenParser checker = new DynamicCheckerTokenParser();
//使用TokenHandler创建GenericTokenParser
GenericTokenParser parser = createParser(checker);
//如果是动态sql,DynamicCheckerTokenParser会修改属性isDynamic
parser.parse(text);
return checker.isDynamic();
}
//获取sql添加到context
public boolean apply(DynamicContext context) {
//使用BindingTokenParser创建GenericTokenParser
GenericTokenParser parser = createParser(new BindingTokenParser(context));
//获取sql添加到context
context.appendSql(parser.parse(text));
return true;
}
//创建GenericTokenParser
private GenericTokenParser createParser(TokenHandler handler) {
return new GenericTokenParser("${", "}", handler);
}
}
//StaticTextSqlNode用来解析SQL文本节点,但是不包含${}
public class StaticTextSqlNode implements SqlNode {
//sql文本
private String text;
public StaticTextSqlNode(String text) {
this.text = text;
}
//获取sql添加到context
public boolean apply(DynamicContext context) {
context.appendSql(text);
return true;
}
}
//VarDeclSqlNode用来解析bind节点,主要用来绑定变量
public class VarDeclSqlNode implements SqlNode {
//上下文的变量名
private final String name;
//OGNL表达式
private final String expression;
public VarDeclSqlNode(String var, String exp) {
name = var;
expression = exp;
}
public boolean apply(DynamicContext context) {
final Object value = OgnlCache.getValue(expression, context.getBindings());
//将值绑定到上下文
context.bind(name, value);
return true;
}
}
//TrimSqlNode用来解析trim节点,主要用来在sql首尾添加字符和删除字符
public class TrimSqlNode implements SqlNode {
//包含的SqlNode
private SqlNode contents;
//前缀
private String prefix;
//后缀
private String suffix;
//sql开头遇到这些字符需要替换为空
private List<String> prefixesToOverride;
//sql结尾遇到这些字符需要替换为空
private List<String> suffixesToOverride;
private Configuration configuration;
//获取sql添加到context
public boolean apply(DynamicContext context) {
//使用FilteredDynamicContext代理DynamicContext
FilteredDynamicContext filteredDynamicContext = new FilteredDynamicContext(context);
//获取sql添加到FilteredDynamicContext
boolean result = contents.apply(filteredDynamicContext);
//获取sql添加到DynamicContext
filteredDynamicContext.applyAll();
return result;
}
//将|连接的字符串分割成数组
private static List<String> parseOverrides(String overrides)
private class FilteredDynamicContext{
//代理的DynamicContext
private DynamicContext delegate;
//prefix是否添加
private boolean prefixApplied;
//suffix是否添加
private boolean suffixApplied;
//临时存储sql
private StringBuilder sqlBuffer;
//重写父类的appendSql,临时存储sql在sqlBuffer
@Override
public void appendSql(String sql) {
sqlBuffer.append(sql);
}
//如果sqlBuffer不空,则使用applyPrefix、applySuffix修改sqlBuffer,再修改代理的DynamicContext
public void applyAll() {
sqlBuffer = new StringBuilder(sqlBuffer.toString().trim());
String trimmedUppercaseSql = sqlBuffer.toString().toUpperCase(Locale.ENGLISH);
if (trimmedUppercaseSql.length() > 0) {
applyPrefix(sqlBuffer, trimmedUppercaseSql);
applySuffix(sqlBuffer, trimmedUppercaseSql);
}
delegate.appendSql(sqlBuffer.toString());
}
}
}
//WhereSqlNode用来解析where节点,在sql首部添加where和首部删除and、or
public class WhereSqlNode extends TrimSqlNode {
private static List<String> prefixList = Arrays.asList("AND ","OR ","AND\n", "OR\n", "AND\r", "OR\r", "AND\t", "OR\t");
//其实就是TrimSqlNode,添加where,去掉开头的and、or关键字
public WhereSqlNode(Configuration configuration, SqlNode contents) {
super(configuration, contents, "WHERE", prefixList, null, null);
}
}
//SetSqlNode用来解析set节点,在sql首部添加set和尾部删除,
public class SetSqlNode extends TrimSqlNode {
private static List<String> suffixList = Arrays.asList(",");
//其实就是TrimSqlNode,添加set,去掉尾部的,
public SetSqlNode(Configuration configuration,SqlNode contents) {
super(configuration, contents, "SET", null, null, suffixList);
}
}
//ForEachSqlNode用来解析foreach节点,来遍历集合
public class ForEachSqlNode implements SqlNode {
public static final String ITEM_PREFIX = "__frch_";
private ExpressionEvaluator evaluator;
//集合
private String collectionExpression;
//包含的SqlNode
private SqlNode contents;
//开头添加的字符串
private String open;
//结尾添加的字符串
private String close;
//分割符
private String separator;
//集合项
private String item;
//索引
private String index;
private Configuration configuration;
public boolean apply(DynamicContext context) {
//添加open
applyOpen(context);
int i = 0;
//对集合对象遍历
for (Object o : iterable) {
//备份context
DynamicContext oldContext = context;
if (first) {
//第一个不需要添加前缀
context = new PrefixedContext(context, "");
} else {
if (separator != null) {
//当separator不空且非第一个时需要添加前缀,
context = new PrefixedContext(context, separator);
} else {
context = new PrefixedContext(context, "");
}
}
//生成序列号
int uniqueNumber = context.getUniqueNumber();
//将index和i关联,item和o关联
if (o instanceof Map.Entry) { // Issue #709
@SuppressWarnings("unchecked")
Map.Entry<Object, Object> mapEntry = (Map.Entry<Object, Object>) o;
applyIndex(context, mapEntry.getKey(), uniqueNumber);
applyItem(context, mapEntry.getValue(), uniqueNumber);
} else {
applyIndex(context, i, uniqueNumber);
applyItem(context, o, uniqueNumber);
}
//FilteredDynamicContext替换其中的index和item,将sql添加到context
contents.apply(new FilteredDynamicContext(configuration, context, index, item, uniqueNumber));
//如果PrefixedContext的prefixApplied为true说明添加了前缀,这时first就为false
if (first) first = !((PrefixedContext) context).isPrefixApplied();
//还原 context
context = oldContext;
i++;
}
//添加colse
applyClose(context);
return true;
}
public FilteredDynamicContext(Configuration configuration,DynamicContext delegate, String itemIndex, String item, int i) {
super(configuration, null);
//代理的DynamicContext
this.delegate = delegate;
//顺序
this.index = i;
//foreach的index
this.itemIndex = itemIndex;
//foreach的item
this.item = item;
}
@Override
public Map<String, Object> getBindings() {
return delegate.getBindings();
}
@Override
public void bind(String name, Object value) {
delegate.bind(name, value);
}
@Override
public String getSql() {
return delegate.getSql();
}
@Override
public void appendSql(String sql) {
GenericTokenParser parser = new GenericTokenParser("#{", "}", new TokenHandler() {
public String handleToken(String content) {
//替换foreach的item
String newContent = content.replaceFirst("^\\s*" + item + "(?![^.,:\\s])", itemizeItem(item, index));
if (itemIndex != null && newContent.equals(content)) {
//替换foreach的index
newContent = content.replaceFirst("^\\s*" + itemIndex + "(?![^.,:\\s])", itemizeItem(itemIndex, index));
}
return new StringBuilder("#{").append(newContent).append("}").toString();
}
});
delegate.appendSql(parser.parse(sql));
}
@Override
public int getUniqueNumber() {
return delegate.getUniqueNumber();
}
}
//IfSqlNode用来解析if节点
public class IfSqlNode implements SqlNode {
private ExpressionEvaluator evaluator;
//test的表达式
private String test;
//包含的SqlNode
private SqlNode contents;
public IfSqlNode(SqlNode contents, String test) {
this.test = test;
this.contents = contents;
this.evaluator = new ExpressionEvaluator();
}
public boolean apply(DynamicContext context) {
if (evaluator.evaluateBoolean(test, context.getBindings())) {
//test判断正确,则添加sql到context
contents.apply(context);
return true;
}
return false;
}
}
//ChooseSqlNode用来解析choose节点
public class ChooseSqlNode implements SqlNode {
//default的SqlNode
private SqlNode defaultSqlNode;
//when的SqlNode
private List<SqlNode> ifSqlNodes;
public ChooseSqlNode(List<SqlNode> ifSqlNodes, SqlNode defaultSqlNode) {
this.ifSqlNodes = ifSqlNodes;
this.defaultSqlNode = defaultSqlNode;
}
public boolean apply(DynamicContext context) {
for (SqlNode sqlNode : ifSqlNodes) {
//如果if的SqlNode添加成功则返回
if (sqlNode.apply(context)) {
return true;
}
}
if (defaultSqlNode != null) {
//否则默认的SqlNode添加成功返回
defaultSqlNode.apply(context);
return true;
}
return false;
}
}
3.3、获取SqlSession
SqlSessionFactory获取SqlSession,DefaultSqlSessionFactory是SqlSessionFactory默认实现类
//SqlSession工厂
public interface SqlSessionFactory {
SqlSession openSession;
Configuration getConfiguration();
}
public class DefaultSqlSessionFactory implements SqlSessionFactory {
private final Configuration configuration;
//通过数据源创建SqlSession
private SqlSession openSessionFromDataSource(ExecutorType execType,
TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
//获取当前执行环境,这里面有TransactionFactory和DataSource
final Environment environment = configuration.getEnvironment();
//获取配置的TransactionFactory,一般是JDBC
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
//使用TransactionFactory创建Transaction,需要DataSource,事务隔离级别,是否事务
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//根据ExecutorType和Transaction创建最重要的Executor,即执行器
final Executor executor = configuration.newExecutor(tx, execType);
//创建DefaultSqlSession,包含了configuration、executor
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
//通过数据库连接Connection创建SqlSession
private SqlSession openSessionFromConnection(ExecutorType execType,
Connection connection) {
try {
boolean autoCommit;
try {
autoCommit = connection.getAutoCommit();
} catch (SQLException e) {
// Failover to true, as most poor drivers
// or databases won't support transactions
autoCommit = true;
}
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
//使用TransactionFactory创建Transaction,需要Connection
final Transaction tx = transactionFactory.newTransaction(connection);
//根据ExecutorType和Transaction创建最重要的Executor,即执行器
final Executor executor = configuration.newExecutor(tx, execType);
//创建DefaultSqlSession,包含了configuration、executor
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
if (environment == null || environment.getTransactionFactory() == null) {
return new ManagedTransactionFactory();
}
return environment.getTransactionFactory();
}
private void closeTransaction(Transaction tx) {
if (tx != null) {
try {
tx.close();
} catch (SQLException ignore) {
// Intentionally ignore. Prefer previous error.
}
}
}
}
3.4、获取mapper
DefaultSqlSession获取mapper,调用configuration的getMapper,调用mapperRegistry的getMapper
public class MapperRegistry {
private Configuration config;
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();
public MapperRegistry(Configuration config) {
this.config = config;
}
@SuppressWarnings("unchecked")
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
//获取type对应的MapperProxyFactory,这个是在解析时创建的
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null)
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
try {
//使用MapperProxyFactory创建type实例
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
//判断是否存在type对应的MapperProxyFactory
public <T> boolean hasMapper(Class<T> type) {
return knownMappers.containsKey(type);
}
//添加type对应的MapperProxyFactory
public <T> void addMapper(Class<T> type) {
if (type.isInterface()) {
if (hasMapper(type)) {
throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
}
boolean loadCompleted = false;
try {
knownMappers.put(type, new MapperProxyFactory<T>(type));
// It's important that the type is added before the parser is run
// otherwise the binding may automatically be attempted by the
// mapper parser. If the type is already known, it won't try.
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
parser.parse();
loadCompleted = true;
} finally {
if (!loadCompleted) {
knownMappers.remove(type);
}
}
}
}
}
public class MapperProxyFactory<T> {
//mapper的class
private final Class<T> mapperInterface;
//MapperMethod缓存
private Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
//使用jdk动态代理生成mapper代理类
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
//创建mapperProxy
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
}
public class MapperProxy<T> implements InvocationHandler, Serializable {
private static final long serialVersionUID = -6424540398559729838L;
private final SqlSession sqlSession;
//mapper的class
private final Class<T> mapperInterface;
//MapperMethod缓存
private final Map<Method, MapperMethod> methodCache;
public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
this.sqlSession = sqlSession;
this.mapperInterface = mapperInterface;
this.methodCache = methodCache;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//如果调用方法类是对象,则直接调用对象的方法
if (Object.class.equals(method.getDeclaringClass())) {
try {
return method.invoke(this, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
//调用MapperMethod的方法
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
private MapperMethod cachedMapperMethod(Method method) {
MapperMethod mapperMethod = methodCache.get(method);
if (mapperMethod == null) {
mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
methodCache.put(method, mapperMethod);
}
return mapperMethod;
}
}
public class MapperMethod {
//方法id和sql类型组合对象
private final SqlCommand command;
//方法签名,包含返回类型、是否void、是否集合、返回map、mapkey,参数是否named,RowBounds的index,ResultHandler的index,参数名map
private final MethodSignature method;
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
//如果插入
if (SqlCommandType.INSERT == command.getType()) {
//将形参转换成对象
Object param = method.convertArgsToSqlCommandParam(args);
//调用sqlSession.insert
result = rowCountResult(sqlSession.insert(command.getName(), param));
} else if (SqlCommandType.UPDATE == command.getType()) {
//将形参转换成对象
Object param = method.convertArgsToSqlCommandParam(args);
//调用sqlSession.update
result = rowCountResult(sqlSession.update(command.getName(), param));
} else if (SqlCommandType.DELETE == command.getType()) {
//将形参转换成对象
Object param = method.convertArgsToSqlCommandParam(args);
//调用sqlSession.delete
result = rowCountResult(sqlSession.delete(command.getName(), param));
} else if (SqlCommandType.SELECT == command.getType()) {
//方法返回void并且参数有ResultHandler实例
if (method.returnsVoid() && method.hasResultHandler()) {
//executeWithResultHandler调用sqlSession.select参数中有ResultHandler实例
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
//executeForMany调用sqlSession.<E>selectList
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
//executeForMap调用sqlSession.<K, V>selectMap
result = executeForMap(sqlSession, args);
} else {
//调用sqlSession.selectOne
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
}
} else {
throw new BindingException("Unknown execution method for: " + command.getName());
}
if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
throw new BindingException("Mapper method '" + command.getName()
+ " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
}
return result;
}
//根据方法签名返回类型和rowCount设置返回值
private Object rowCountResult(int rowCount)
//将参数转换成对象,如果参数中有RowBounds实例,则带上RowBounds实例,从参数中获取ResultHandler实例,调用sqlSession.select
private void executeWithResultHandler()
//将参数转换成对象,如果参数中有RowBounds实例,则带上RowBounds实例,调用sqlSession.<E>selectList
private <E> Object executeForMany()
//将参数转换成对象,如果参数中有RowBounds实例,则带上RowBounds实例,获取mapkey,调用sqlSession.<K, V>selectMap
private <K, V> Map<K, V> executeForMap()
//多个参数封装对象
public static class ParamMap<V> extends HashMap<String, V> {}
//sql类型和方法名称封装
public static class SqlCommand {
//方法id,包含命名空间
private final String name;
//sql类型
private final SqlCommandType type;
public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) throws BindingException {
//构造statementName
String statementName = mapperInterface.getName() + "." + method.getName();
MappedStatement ms = null;
//获取MappedStatement
if (configuration.hasStatement(statementName)) {
ms = configuration.getMappedStatement(statementName);
} else if (!mapperInterface.equals(method.getDeclaringClass().getName())) { // issue #35
String parentStatementName = method.getDeclaringClass().getName() + "." + method.getName();
if (configuration.hasStatement(parentStatementName)) {
ms = configuration.getMappedStatement(parentStatementName);
}
}
if (ms == null) {
throw new BindingException("Invalid bound statement (not found): " + statementName);
}
name = ms.getId();
type = ms.getSqlCommandType();
if (type == SqlCommandType.UNKNOWN) {
throw new BindingException("Unknown execution method for: " + name);
}
}
}
public static class MethodSignature {
//方法是否返回集合
private final boolean returnsMany;
//方法是否返回map
private final boolean returnsMap;
//方法是否返回void
private final boolean returnsVoid;
//方法返回类型
private final Class<?> returnType;
//返回map指定的key
private final String mapKey;
//参数中ResultHandler实例的index
private final Integer resultHandlerIndex;
//参数中RowBounds实例的index
private final Integer rowBoundsIndex;
//参数别名
private final SortedMap<Integer, String> params;
//是否有named参数
private final boolean hasNamedParameters;
public MethodSignature(Configuration configuration, Method method) throws BindingException {
this.returnType = method.getReturnType();
this.returnsVoid = void.class.equals(this.returnType);
this.returnsMany = (configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray());
this.mapKey = getMapKey(method);
this.returnsMap = (this.mapKey != null);
this.hasNamedParameters = hasNamedParams(method);
//获取RowBounds类型参数下标,如果有多个,则用第一个
this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
//遍历方法定义参数,key是方法参数下标,value是别名,从0开始,如果使用param注解,则替换成param注解指定的name
this.params = Collections.unmodifiableSortedMap(getParams(method, this.hasNamedParameters));
}
public Object convertArgsToSqlCommandParam(Object[] args) {
final int paramCount = params.size();
if (args == null || paramCount == 0) {
//形参是null或者方法参数个数是0直接返回null
return null;
} else if (!hasNamedParameters && paramCount == 1) {
//参数个数是1,并且没有别名
return args[params.keySet().iterator().next()];
} else {
final Map<String, Object> param = new ParamMap<Object>();
int i = 0;
//这里构造参数的时候使用了两个定义,一个是0,1,2...,一个是param1,param2
for (Map.Entry<Integer, String> entry : params.entrySet()) {
param.put(entry.getValue(), args[entry.getKey()]);
// issue #71, add param names as param1, param2...but ensure backward compatibility
final String genericParamName = "param" + String.valueOf(i + 1);
if (!param.containsKey(genericParamName)) {
param.put(genericParamName, args[entry.getKey()]);
}
i++;
}
return param;
}
}
//获取方法参数类型和paramType相同的参数下标
private Integer getUniqueParamIndex(Method method, Class<?> paramType)
//获取方法返回类型是map时方法注解MapKey的value
private String getMapKey(Method method)
//获取方法参数下标和别名map,别名是从0开始,有Param注解则用注解指定的别名
private SortedMap<Integer, String> getParams(Method method, boolean hasNamedParameters) {
final SortedMap<Integer, String> params = new TreeMap<Integer, String>();
final Class<?>[] argTypes = method.getParameterTypes();
for (int i = 0; i < argTypes.length; i++) {
if (!RowBounds.class.isAssignableFrom(argTypes[i]) && !ResultHandler.class.isAssignableFrom(argTypes[i])) {
String paramName = String.valueOf(params.size());
if (hasNamedParameters) {
paramName = getParamNameFromAnnotation(method, i, paramName);
}
params.put(i, paramName);
}
}
return params;
}
//获取Param注解指定的值
private String getParamNameFromAnnotation(Method method, int i, String paramName) {
final Object[] paramAnnos = method.getParameterAnnotations()[i];
for (Object paramAnno : paramAnnos) {
if (paramAnno instanceof Param) {
paramName = ((Param) paramAnno).value();
}
}
return paramName;
}
//方法是否有指定的参数
private boolean hasNamedParams(Method method) {
boolean hasNamedParams = false;
final Object[][] paramAnnos = method.getParameterAnnotations();
for (Object[] paramAnno : paramAnnos) {
for (Object aParamAnno : paramAnno) {
if (aParamAnno instanceof Param) {
hasNamedParams = true;
break;
}
}
}
return hasNamedParams;
}
}
}
3.5、DefaultSqlSession执行sql
DefaultSqlSession执行sql,select、update、insert、delete、commit、rollback
public class DefaultSqlSession implements SqlSession {
//configuration
private Configuration configuration;
//执行器
private Executor executor;
//自动提交
private boolean autoCommit;
private boolean dirty;
public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
this.configuration = configuration;
this.executor = executor;
this.dirty = false;
this.autoCommit = autoCommit;
}
public DefaultSqlSession(Configuration configuration, Executor executor) {
this(configuration, executor, false);
}
//查询一条数据
public <T> T selectOne(String statement) {
return this.<T>selectOne(statement, null);
}
//带参数查询一条数据
public <T> T selectOne(String statement, Object parameter) {
// Popular vote was to return null on 0 results and throw exception on too many.
//调用selectList
List<T> list = this.<T>selectList(statement, parameter);
if (list.size() == 1) {
return list.get(0);
} else if (list.size() > 1) {
throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
} else {
return null;
}
}
//查询map
public <K, V> Map<K, V> selectMap(String statement, String mapKey) {
return this.selectMap(statement, null, mapKey, RowBounds.DEFAULT);
}
//带参数查询map
public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {
return this.selectMap(statement, parameter, mapKey, RowBounds.DEFAULT);
}
//带参数和RowBounds查询map
public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
final List<?> list = selectList(statement, parameter, rowBounds);
//创建ResultHandler
final DefaultMapResultHandler<K, V> mapResultHandler = new DefaultMapResultHandler<K, V>(mapKey,
configuration.getObjectFactory(), configuration.getObjectWrapperFactory());
final DefaultResultContext context = new DefaultResultContext();
for (Object o : list) {
context.nextResultObject(o);
mapResultHandler.handleResult(context);
}
Map<K, V> selectedMap = mapResultHandler.getMappedResults();
return selectedMap;
}
//查询多条数据
public <E> List<E> selectList(String statement) {
return this.selectList(statement, null);
}
//带参数查询多条数据
public <E> List<E> selectList(String statement, Object parameter) {
return this.selectList(statement, parameter, RowBounds.DEFAULT);
}
//带参数和RowBounds查询多条数据
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
//调用执行器查询
List<E> result = executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
return result;
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
//带参数和ResultHandler查询
public void select(String statement, Object parameter, ResultHandler handler) {
select(statement, parameter, RowBounds.DEFAULT, handler);
}
//带ResultHandler查询
public void select(String statement, ResultHandler handler) {
select(statement, null, RowBounds.DEFAULT, handler);
}
//带参数和RowBounds和ResultHandler查询
public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
//调用执行器查询
executor.query(ms, wrapCollection(parameter), rowBounds, handler);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
//插入
public int insert(String statement) {
return insert(statement, null);
}
//带参数插入
public int insert(String statement, Object parameter) {
return update(statement, parameter);
}
//更新
public int update(String statement) {
return update(statement, null);
}
//带参数更新
public int update(String statement, Object parameter) {
try {
dirty = true;
MappedStatement ms = configuration.getMappedStatement(statement);
return executor.update(ms, wrapCollection(parameter));
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
//删除
public int delete(String statement) {
return update(statement, null);
}
//带参数删除
public int delete(String statement, Object parameter) {
return update(statement, parameter);
}
//提交
public void commit() {
commit(false);
}
public void commit(boolean force) {
try {
//调用执行器的commit
executor.commit(isCommitOrRollbackRequired(force));
dirty = false;
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error committing transaction. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
//回滚
public void rollback() {
rollback(false);
}
public void rollback(boolean force) {
try {
//调用执行器回滚
executor.rollback(isCommitOrRollbackRequired(force));
dirty = false;
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error rolling back transaction. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
//flush
public List<BatchResult> flushStatements() {
try {
//调用执行器flush
return executor.flushStatements();
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error flushing statements. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
//关闭
public void close() {
try {
//调用执行器关闭
executor.close(isCommitOrRollbackRequired(false));
dirty = false;
} finally {
ErrorContext.instance().reset();
}
}
//获取Configuration
public Configuration getConfiguration() {
return configuration;
}
//获取mapper
public <T> T getMapper(Class<T> type) {
return configuration.<T>getMapper(type, this);
}
//获取连接
public Connection getConnection() {
try {
//从执行器的Transaction获取连接
return executor.getTransaction().getConnection();
} catch (SQLException e) {
throw ExceptionFactory.wrapException("Error getting a new connection. Cause: " + e, e);
}
}
}
3.6、Executor执行sql
DefaultSqlSession委托Executor实现select、update、insert、delete、commit、rollback
//执行器父类
public abstract class BaseExecutor implements Executor {
private static final Log log = LogFactory.getLog(BaseExecutor.class);
//事务
protected Transaction transaction;
//自己引用自己
protected Executor wrapper;
protected ConcurrentLinkedQueue<DeferredLoad> deferredLoads;
//本地缓存
protected PerpetualCache localCache;
//callable使用的本地缓存
protected PerpetualCache localOutputParameterCache;
protected Configuration configuration;
//查询量
protected int queryStack = 0;
//执行器是否关闭
private boolean closed;
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
if (closed) throw new ExecutorException("Executor was closed.");
//如果查询量是0并且MappedStatement需要刷新缓存
if (queryStack == 0 && ms.isFlushCacheRequired()) {
clearLocalCache();
}
List<E> list;
try {
queryStack++;
//从本地缓存中获取
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
if (list != null) {
//callable从缓存中获取
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
//从数据库查询
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
queryStack--;
}
if (queryStack == 0) {
for (DeferredLoad deferredLoad : deferredLoads) {
deferredLoad.load();
}
deferredLoads.clear(); // issue #601
//如果本地缓存范围是statement,则清除本地缓存
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
clearLocalCache(); // issue #482
}
}
return list;
}
//创建CacheKey
public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql)
//从数据库查询
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
List<E> list;
localCache.putObject(key, EXECUTION_PLACEHOLDER);
try {
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
localCache.removeObject(key);
}
//设置本地缓存
localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
localOutputParameterCache.putObject(key, parameter);
}
return list;
}
//MappedStatement是否缓存
public boolean isCached(MappedStatement ms, CacheKey key)
//执行器提交
public void commit(boolean required)
//执行器回滚
public void rollback(boolean required)
//清除本地缓存
public void clearLocalCache()
}
public class SimpleExecutor extends BaseExecutor {
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
//创建StatementHandler
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
//通过StatementHandler获取Statement
stmt = prepareStatement(handler, ms.getStatementLog());
//执行StatementHandler的update
return handler.update(stmt);
} finally {
closeStatement(stmt);
}
}
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
stmt = prepareStatement(handler, ms.getStatementLog());
//执行StatementHandler的//执行StatementHandler的update
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
//清空statement
public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
return Collections.emptyList();
}
//返回Statement
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
Connection connection = getConnection(statementLog);
stmt = handler.prepare(connection);
handler.parameterize(stmt);
return stmt;
}
}
public class ReuseExecutor extends BaseExecutor {
//Statement缓存
private final Map<String, Statement> statementMap = new HashMap<String, Statement>();
//同SimpleRxecutor
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
Statement stmt = prepareStatement(handler, ms.getStatementLog());
return handler.update(stmt);
}
//同SimpleExecutor
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
Statement stmt = prepareStatement(handler, ms.getStatementLog());
return handler.<E>query(stmt, resultHandler);
}
//清空statement
public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
for (Statement stmt : statementMap.values()) {
closeStatement(stmt);
}
statementMap.clear();
return Collections.emptyList();
}
//区别于SimpleStatement,这里使用了缓存
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
BoundSql boundSql = handler.getBoundSql();
String sql = boundSql.getSql();
//sql是否有Statement缓存
if (hasStatementFor(sql)) {
//从缓存中获取Statement
stmt = getStatement(sql);
} else {
//获取数据库连接创建Statement
Connection connection = getConnection(statementLog);
stmt = handler.prepare(connection);
putStatement(sql, stmt);
}
handler.parameterize(stmt);
return stmt;
}
}
public class BatchExecutor extends BaseExecutor {
public static final int BATCH_UPDATE_RETURN_VALUE = Integer.MIN_VALUE + 1002;
//Statement数组
private final List<Statement> statementList = new ArrayList<Statement>();
//批处理结果
private final List<BatchResult> batchResultList = new ArrayList<BatchResult>();
//当前sql
private String currentSql;
//当前MappedStatement
private MappedStatement currentStatement;
public int doUpdate(MappedStatement ms, Object parameterObject) throws SQLException {
final Configuration configuration = ms.getConfiguration();
final StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, RowBounds.DEFAULT, null, null);
final BoundSql boundSql = handler.getBoundSql();
final String sql = boundSql.getSql();
final Statement stmt;
//如果sql和当前sql相同,MappedStatement也相同
if (sql.equals(currentSql) && ms.equals(currentStatement)) {
int last = statementList.size() - 1;
//取出上一条Statement
stmt = statementList.get(last);
//取出上一条批处理结果
BatchResult batchResult = batchResultList.get(last);
//将当前参数添加到批处理结果集中
batchResult.addParameterObject(parameterObject);
} else {
//获取一个数据库连接创建Statement
Connection connection = getConnection(ms.getStatementLog());
stmt = handler.prepare(connection);
currentSql = sql;
currentStatement = ms;
statementList.add(stmt);
batchResultList.add(new BatchResult(ms, sql, parameterObject));
}
//Statement设置预编译参数
handler.parameterize(stmt);
//Statement设置批处理
handler.batch(stmt);
return BATCH_UPDATE_RETURN_VALUE;
}
public <E> List<E> doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
throws SQLException {
Statement stmt = null;
try {
//查询之前会清空Statement
flushStatements();
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameterObject, rowBounds, resultHandler, boundSql);
Connection connection = getConnection(ms.getStatementLog());
stmt = handler.prepare(connection);
handler.parameterize(stmt);
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
try {
List<BatchResult> results = new ArrayList<BatchResult>();
if (isRollback) {
return Collections.emptyList();
} else {
for (int i = 0, n = statementList.size(); i < n; i++) {
Statement stmt = statementList.get(i);
BatchResult batchResult = batchResultList.get(i);
try {
//每一个Statement执行executeBatch
batchResult.setUpdateCounts(stmt.executeBatch());
MappedStatement ms = batchResult.getMappedStatement();
List<Object> parameterObjects = batchResult.getParameterObjects();
KeyGenerator keyGenerator = ms.getKeyGenerator();
//执行key
if (Jdbc3KeyGenerator.class.equals(keyGenerator.getClass())) {
Jdbc3KeyGenerator jdbc3KeyGenerator = (Jdbc3KeyGenerator) keyGenerator;
jdbc3KeyGenerator.processBatch(ms, stmt, parameterObjects);
} else if (!NoKeyGenerator.class.equals(keyGenerator.getClass())) { //issue #141
for (Object parameter : parameterObjects) {
keyGenerator.processAfter(this, ms, stmt, parameter);
}
}
} catch (BatchUpdateException e) {
StringBuffer message = new StringBuffer();
message.append(batchResult.getMappedStatement().getId())
.append(" (batch index #")
.append(i + 1)
.append(")")
.append(" failed.");
if (i > 0) {
message.append(" ")
.append(i)
.append(" prior sub executor(s) completed successfully, but will be rolled back.");
}
throw new BatchExecutorException(message.toString(), e, results, batchResult);
}
results.add(batchResult);
}
return results;
}
} finally {
for (Statement stmt : statementList) {
closeStatement(stmt);
}
currentSql = null;
statementList.clear();
batchResultList.clear();
}
}
}
public class CachingExecutor implements Executor {
//代理Executor
private Executor delegate;
//缓存管理器
private TransactionalCacheManager tcm = new TransactionalCacheManager();
public void close(boolean forceRollback) {
try {
//issues #499, #524 and #573
if (forceRollback) {
tcm.rollback();
} else {
tcm.commit();
}
} finally {
delegate.close(forceRollback);
}
}
public boolean isClosed() {
return delegate.isClosed();
}
public int update(MappedStatement ms, Object parameterObject) throws SQLException {
flushCacheIfRequired(ms);
return delegate.update(ms, parameterObject);
}
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
BoundSql boundSql = ms.getBoundSql(parameterObject);
CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
Cache cache = ms.getCache();
if (cache != null) {
flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, parameterObject, boundSql);
@SuppressWarnings("unchecked")
List<E> list = (List<E>) tcm.getObject(cache, key);
if (list == null) {
list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578. Query must be not synchronized to prevent deadlocks
}
return list;
}
}
return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
public List<BatchResult> flushStatements() throws SQLException {
return delegate.flushStatements();
}
public void commit(boolean required) throws SQLException {
delegate.commit(required);
tcm.commit();
}
public void rollback(boolean required) throws SQLException {
try {
delegate.rollback(required);
} finally {
if (required) {
tcm.rollback();
}
}
}
private void ensureNoOutParams(MappedStatement ms, Object parameter, BoundSql boundSql) {
if (ms.getStatementType() == StatementType.CALLABLE) {
for (ParameterMapping parameterMapping : boundSql.getParameterMappings()) {
if (parameterMapping.getMode() != ParameterMode.IN) {
throw new ExecutorException("Caching stored procedures with OUT params is not supported. Please configure useCache=false in " + ms.getId() + " statement.");
}
}
}
}
public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
return delegate.createCacheKey(ms, parameterObject, rowBounds, boundSql);
}
public boolean isCached(MappedStatement ms, CacheKey key) {
return delegate.isCached(ms, key);
}
public void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType) {
delegate.deferLoad(ms, resultObject, property, key, targetType);
}
public void clearLocalCache() {
delegate.clearLocalCache();
}
private void flushCacheIfRequired(MappedStatement ms) {
Cache cache = ms.getCache();
if (cache != null && ms.isFlushCacheRequired()) {
tcm.clear(cache);
}
}
@Override
public void setExecutorWrapper(Executor executor) {
throw new UnsupportedOperationException("This method should not be called");
}
}
3.7、获取BoundSql
MappedStatement的getBoundSql是获取BoundSql对象,这个对象是给接下来的Executor使用,主要通过DynamicSqlSource和RawSqlSource获取
public class DynamicSqlSource implements SqlSource {
private Configuration configuration;
private SqlNode rootSqlNode;
public DynamicSqlSource(Configuration configuration, SqlNode rootSqlNode) {
this.configuration = configuration;
this.rootSqlNode = rootSqlNode;
}
public BoundSql getBoundSql(Object parameterObject) {
//创建DynamicContext
DynamicContext context = new DynamicContext(configuration, parameterObject);
//拼接sql和缓存参数到context中
rootSqlNode.apply(context);
//创建SqlSourceBuilder
SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
//替换sql中的#和构造相应的ParameterMapping,生成StaticSqlSource
SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
//创建BoundSql
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) {
boundSql.setAdditionalParameter(entry.getKey(), entry.getValue());
}
return boundSql;
}
}
public class RawSqlSource implements SqlSource {
private final SqlSource sqlSource;
public RawSqlSource(Configuration configuration, SqlNode rootSqlNode, Class<?> parameterType) {
this(configuration, getSql(configuration, rootSqlNode), parameterType);
}
public RawSqlSource(Configuration configuration, String sql, Class<?> parameterType) {
//创建SqlSourceBuilder
SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
Class<?> clazz = parameterType == null ? Object.class : parameterType;
//替换sql中的#和构造相应的ParameterMapping,生成StaticSqlSource
sqlSource = sqlSourceParser.parse(sql, clazz, new HashMap<String, Object>());
}
private static String getSql(Configuration configuration, SqlNode rootSqlNode) {
DynamicContext context = new DynamicContext(configuration, null);
rootSqlNode.apply(context);
return context.getSql();
}
public BoundSql getBoundSql(Object parameterObject) {
return sqlSource.getBoundSql(parameterObject);
}
}
public class StaticSqlSource implements SqlSource {
//执行的预编译sql
private String sql;
//参数
private List<ParameterMapping> parameterMappings;
private Configuration configuration;
public StaticSqlSource(Configuration configuration, String sql) {
this(configuration, sql, null);
}
public StaticSqlSource(Configuration configuration, String sql, List<ParameterMapping> parameterMappings) {
this.sql = sql;
this.parameterMappings = parameterMappings;
this.configuration = configuration;
}
public BoundSql getBoundSql(Object parameterObject) {
return new BoundSql(configuration, sql, parameterMappings, parameterObject);
}
}
public class SqlSourceBuilder extends BaseBuilder {
private static final String parameterProperties = "javaType,jdbcType,mode,numericScale,resultMap,typeHandler,jdbcTypeName";
public SqlSourceBuilder(Configuration configuration) {
super(configuration);
}
public SqlSource parse(String originalSql, Class<?> parameterType, Map<String, Object> additionalParameters) {
//替换#{}中的内容为?,并构造ParameterMapping
ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType, additionalParameters);
GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);
String sql = parser.parse(originalSql);
//创建StaticSqlSource
return new StaticSqlSource(configuration, sql, handler.getParameterMappings());
}
private static class ParameterMappingTokenHandler extends BaseBuilder implements TokenHandler {
//存储ParameterMapping
private List<ParameterMapping> parameterMappings = new ArrayList<ParameterMapping>();
//参数类型
private Class<?> parameterType;
//之前解析绑定的变量
private MetaObject metaParameters;
public ParameterMappingTokenHandler(Configuration configuration, Class<?> parameterType, Map<String, Object> additionalParameters) {
super(configuration);
this.parameterType = parameterType;
this.metaParameters = configuration.newMetaObject(additionalParameters);
}
public List<ParameterMapping> getParameterMappings() {
return parameterMappings;
}
public String handleToken(String content) {
//添加ParameterMapping到parameterMappings
parameterMappings.add(buildParameterMapping(content));
//将?添加到sql
return "?";
}
private ParameterMapping buildParameterMapping(String content) {
Map<String, String> propertiesMap = parseParameterMapping(content);
//解析属性名
String property = propertiesMap.get("property");
Class<?> propertyType;
//解析属性类型
if (metaParameters.hasGetter(property)) { // issue #448 get type from additional params
propertyType = metaParameters.getGetterType(property);
} else if (typeHandlerRegistry.hasTypeHandler(parameterType)) {
propertyType = parameterType;
} else if (JdbcType.CURSOR.name().equals(propertiesMap.get("jdbcType"))) {
propertyType = java.sql.ResultSet.class;
} else if (property != null) {
MetaClass metaClass = MetaClass.forClass(parameterType);
if (metaClass.hasGetter(property)) {
propertyType = metaClass.getGetterType(property);
} else {
propertyType = Object.class;
}
} else {
propertyType = Object.class;
}
ParameterMapping.Builder builder = new ParameterMapping.Builder(configuration, property, propertyType);
Class<?> javaType = propertyType;
String typeHandlerAlias = null;
for (Map.Entry<String, String> entry : propertiesMap.entrySet()) {
String name = entry.getKey();
String value = entry.getValue();
if ("javaType".equals(name)) {
javaType = resolveClass(value);
builder.javaType(javaType);
} else if ("jdbcType".equals(name)) {
builder.jdbcType(resolveJdbcType(value));
} else if ("mode".equals(name)) {
builder.mode(resolveParameterMode(value));
} else if ("numericScale".equals(name)) {
builder.numericScale(Integer.valueOf(value));
} else if ("resultMap".equals(name)) {
builder.resultMapId(value);
} else if ("typeHandler".equals(name)) {
typeHandlerAlias = value;
} else if ("jdbcTypeName".equals(name)) {
builder.jdbcTypeName(value);
} else if ("property".equals(name)) {
// Do Nothing
} else if ("expression".equals(name)) {
throw new BuilderException("Expression based parameters are not supported yet");
} else {
throw new BuilderException("An invalid property '" + name + "' was found in mapping #{" + content + "}. Valid properties are " + parameterProperties);
}
}
if (typeHandlerAlias != null) {
builder.typeHandler(resolveTypeHandler(javaType, typeHandlerAlias));
}
return builder.build();
}
private Map<String, String> parseParameterMapping(String content) {
try {
return new ParameterExpression(content);
} catch (BuilderException ex) {
throw ex;
} catch (Exception ex) {
throw new BuilderException("Parsing error was found in mapping #{" + content + "}. Check syntax #{property|(expression), var1=value1, var2=value2, ...} ", ex);
}
}
}
}
DynamicContext是获取BoundSql时用来拼接sql,同时存储参数索引和参数值
public class DynamicContext {
public static final String PARAMETER_OBJECT_KEY = "_parameter";
public static final String DATABASE_ID_KEY = "_databaseId";
static {
OgnlRuntime.setPropertyAccessor(ContextMap.class, new ContextAccessor());
}
//变量缓存
private final ContextMap bindings;
//sql
private final StringBuilder sqlBuilder = new StringBuilder();
//数组循环生成的序列
private int uniqueNumber = 0;
public DynamicContext(Configuration configuration, Object parameterObject) {
//创建ContextMap
if (parameterObject != null && !(parameterObject instanceof Map)) {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
bindings = new ContextMap(metaObject);
} else {
bindings = new ContextMap(null);
}
bindings.put(PARAMETER_OBJECT_KEY, parameterObject);
bindings.put(DATABASE_ID_KEY, configuration.getDatabaseId());
}
//获取变量缓存
public Map<String, Object> getBindings() {
return bindings;
}
//缓存变量
public void bind(String name, Object value) {
bindings.put(name, value);
}
//添加sql
public void appendSql(String sql) {
sqlBuilder.append(sql);
sqlBuilder.append(" ");
}
//获取sql
public String getSql() {
return sqlBuilder.toString().trim();
}
//数组循环生成序列
public int getUniqueNumber() {
return uniqueNumber++;
}
//DynamicContext存储变量的map
static class ContextMap extends HashMap<String, Object> {
private static final long serialVersionUID = 2977601501966151582L;
//初始化时的变量
private MetaObject parameterMetaObject;
public ContextMap(MetaObject parameterMetaObject) {
this.parameterMetaObject = parameterMetaObject;
}
@Override
public Object put(String key, Object value) {
return super.put(key, value);
}
//先从map里获取,然后从parameterMetaObject获取
@Override
public Object get(Object key) {
String strKey = (String) key;
if (super.containsKey(strKey)) {
return super.get(strKey);
}
if (parameterMetaObject != null) {
Object object = parameterMetaObject.getValue(strKey);
// issue #61 do not modify the context when reading
// if (object != null) {
// super.put(strKey, object);
// }
return object;
}
return null;
}
}
}
3.8、StatementHandler执行sql
public abstract class BaseStatementHandler implements StatementHandler {
protected final Configuration configuration;
protected final ObjectFactory objectFactory;
protected final TypeHandlerRegistry typeHandlerRegistry;
protected final ResultSetHandler resultSetHandler;
protected final ParameterHandler parameterHandler;
protected final Executor executor;
protected final MappedStatement mappedStatement;
protected final RowBounds rowBounds;
protected BoundSql boundSql;
protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
this.configuration = mappedStatement.getConfiguration();
this.executor = executor;
this.mappedStatement = mappedStatement;
this.rowBounds = rowBounds;
this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
this.objectFactory = configuration.getObjectFactory();
if (boundSql == null) { // issue #435, get the key before calculating the statement
//执行KeyGenerator
generateKeys(parameterObject);
//获取BoundSql
boundSql = mappedStatement.getBoundSql(parameterObject);
}
this.boundSql = boundSql;
//构造ParameterHandler
this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
//构造ResultSetHandler
this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}
public Statement prepare(Connection connection) throws SQLException {
ErrorContext.instance().sql(boundSql.getSql());
Statement statement = null;
try {
//实例化Statement
statement = instantiateStatement(connection);
setStatementTimeout(statement);
setFetchSize(statement);
return statement;
} catch (SQLException e) {
closeStatement(statement);
throw e;
} catch (Exception e) {
closeStatement(statement);
throw new ExecutorException("Error preparing statement. Cause: " + e, e);
}
}
//设置statement的timeout
protected void setStatementTimeout(Statement stmt) throws SQLException {
Integer timeout = mappedStatement.getTimeout();
Integer defaultTimeout = configuration.getDefaultStatementTimeout();
if (timeout != null) {
stmt.setQueryTimeout(timeout);
} else if (defaultTimeout != null) {
stmt.setQueryTimeout(defaultTimeout);
}
}
//设置statement的fetchSize
protected void setFetchSize(Statement stmt) throws SQLException {
Integer fetchSize = mappedStatement.getFetchSize();
if (fetchSize != null) {
stmt.setFetchSize(fetchSize);
}
}
//关闭statement
protected void closeStatement(Statement statement) {
try {
if (statement != null) {
statement.close();
}
} catch (SQLException e) {
//ignore
}
}
//生成key
protected void generateKeys(Object parameter) {
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
ErrorContext.instance().store();
keyGenerator.processBefore(executor, mappedStatement, null, parameter);
ErrorContext.instance().recall();
}
}
public class SimpleStatementHandler extends BaseStatementHandler {
public int update(Statement statement) throws SQLException {
String sql = boundSql.getSql();
Object parameterObject = boundSql.getParameterObject();
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
int rows;
if (keyGenerator instanceof Jdbc3KeyGenerator) {
//执行更新sql和Jdbc3KeyGenerator
statement.execute(sql, Statement.RETURN_GENERATED_KEYS);
rows = statement.getUpdateCount();
keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
} else if (keyGenerator instanceof SelectKeyGenerator) {
//执行更新sql和SelectKeyGenerator
statement.execute(sql);
rows = statement.getUpdateCount();
keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
} else {
statement.execute(sql);
rows = statement.getUpdateCount();
}
return rows;
}
public void batch(Statement statement)
throws SQLException {
//批量执行sql
String sql = boundSql.getSql();
statement.addBatch(sql);
}
public <E> List<E> query(Statement statement, ResultHandler resultHandler)
throws SQLException {
//执行查询sql
String sql = boundSql.getSql();
statement.execute(sql);
//调用resultSetHandler处理结果
return resultSetHandler.<E>handleResultSets(statement);
}
protected Statement instantiateStatement(Connection connection) throws SQLException {
//创建Statement
if (mappedStatement.getResultSetType() != null) {
return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
} else {
return connection.createStatement();
}
}
public void parameterize(Statement statement) throws SQLException {
// N/A
}
}
public class PreparedStatementHandler extends BaseStatementHandler {
public int update(Statement statement) throws SQLException {
//与SimpleStatementHandler区别是使用预编译执行方式
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
int rows = ps.getUpdateCount();
Object parameterObject = boundSql.getParameterObject();
//执行KeyGenerator
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
return rows;
}
public void batch(Statement statement) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.addBatch();
}
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
//与SimpleStatementHandler区别是使用预编译执行方式
PreparedStatement ps = (PreparedStatement) statement;
//调用resultSetHandler处理结果
ps.execute();
return resultSetHandler.<E> handleResultSets(ps);
}
protected Statement instantiateStatement(Connection connection) throws SQLException {
String sql = boundSql.getSql();
if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
String[] keyColumnNames = mappedStatement.getKeyColumns();
if (keyColumnNames == null) {
return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
} else {
return connection.prepareStatement(sql, keyColumnNames);
}
} else if (mappedStatement.getResultSetType() != null) {
return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
} else {
return connection.prepareStatement(sql);
}
}
public void parameterize(Statement statement) throws SQLException {
parameterHandler.setParameters((PreparedStatement) statement);
}
}
public class CallableStatementHandler extends BaseStatementHandler {
public CallableStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
}
public int update(Statement statement)
throws SQLException {
CallableStatement cs = (CallableStatement) statement;
cs.execute();
int rows = cs.getUpdateCount();
Object parameterObject = boundSql.getParameterObject();
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
keyGenerator.processAfter(executor, mappedStatement, cs, parameterObject);
resultSetHandler.handleOutputParameters(cs);
return rows;
}
public void batch(Statement statement)
throws SQLException {
CallableStatement cs = (CallableStatement) statement;
cs.addBatch();
}
public <E> List<E> query(Statement statement, ResultHandler resultHandler)
throws SQLException {
CallableStatement cs = (CallableStatement) statement;
cs.execute();
List<E> resultList = resultSetHandler.<E>handleResultSets(cs);
resultSetHandler.handleOutputParameters(cs);
return resultList;
}
protected Statement instantiateStatement(Connection connection) throws SQLException {
String sql = boundSql.getSql();
if (mappedStatement.getResultSetType() != null) {
return connection.prepareCall(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
} else {
return connection.prepareCall(sql);
}
}
public void parameterize(Statement statement) throws SQLException {
registerOutputParameters((CallableStatement) statement);
parameterHandler.setParameters((CallableStatement) statement);
}
private void registerOutputParameters(CallableStatement cs) throws SQLException {
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
for (int i = 0, n = parameterMappings.size(); i < n; i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
if (parameterMapping.getMode() == ParameterMode.OUT || parameterMapping.getMode() == ParameterMode.INOUT) {
if (null == parameterMapping.getJdbcType()) {
throw new ExecutorException("The JDBC Type must be specified for output parameter. Parameter: " + parameterMapping.getProperty());
} else {
if (parameterMapping.getNumericScale() != null && (parameterMapping.getJdbcType() == JdbcType.NUMERIC || parameterMapping.getJdbcType() == JdbcType.DECIMAL)) {
cs.registerOutParameter(i + 1, parameterMapping.getJdbcType().TYPE_CODE, parameterMapping.getNumericScale());
} else {
if (parameterMapping.getJdbcTypeName() == null) {
cs.registerOutParameter(i + 1, parameterMapping.getJdbcType().TYPE_CODE);
} else {
cs.registerOutParameter(i + 1, parameterMapping.getJdbcType().TYPE_CODE, parameterMapping.getJdbcTypeName());
}
}
}
}
}
}
}
3.9、ParameterHandler处理参数
public class DefaultParameterHandler implements ParameterHandler {
//类型处理器
private final TypeHandlerRegistry typeHandlerRegistry;
private final MappedStatement mappedStatement;
private final Object parameterObject;
private BoundSql boundSql;
private Configuration configuration;
public DefaultParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
this.mappedStatement = mappedStatement;
this.configuration = mappedStatement.getConfiguration();
this.typeHandlerRegistry = mappedStatement.getConfiguration().getTypeHandlerRegistry();
this.parameterObject = parameterObject;
this.boundSql = boundSql;
}
public Object getParameterObject() {
return parameterObject;
}
public void setParameters(PreparedStatement ps) throws SQLException {
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
//获取BoundSql所有参数
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings != null) {
for (int i = 0; i < parameterMappings.size(); i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
//获取参数名称
String propertyName = parameterMapping.getProperty();
//获取参数值
if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
TypeHandler typeHandler = parameterMapping.getTypeHandler();
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) jdbcType = configuration.getJdbcTypeForNull();
typeHandler.setParameter(ps, i + 1, value, jdbcType);
}
}
}
}
}
3.10、ResultSetHandler处理结果
public class DefaultResultSetHandler implements ResultSetHandler {
private static final Object NO_VALUE = new Object();
private final Executor executor;
private final Configuration configuration;
private final MappedStatement mappedStatement;
private final RowBounds rowBounds;
private final ParameterHandler parameterHandler;
private final ResultHandler resultHandler;
private final BoundSql boundSql;
private final TypeHandlerRegistry typeHandlerRegistry;
private final ObjectFactory objectFactory;
// nested resultmaps
private final Map<CacheKey, Object> nestedResultObjects = new HashMap<CacheKey, Object>();
private final Map<CacheKey, Object> ancestorObjects = new HashMap<CacheKey, Object>();
private final Map<String, String> ancestorColumnPrefix = new HashMap<String, String>();
// multiple resultsets
private final Map<String, ResultMapping> nextResultMaps = new HashMap<String, ResultMapping>();
private final Map<CacheKey, List<PendingRelation>> pendingRelations = new HashMap<CacheKey, List<PendingRelation>>();
private static class PendingRelation {
public MetaObject metaObject;
public ResultMapping propertyMapping;
}
public DefaultResultSetHandler(Executor executor, MappedStatement mappedStatement, ParameterHandler parameterHandler, ResultHandler resultHandler, BoundSql boundSql,
RowBounds rowBounds) {
this.executor = executor;
this.configuration = mappedStatement.getConfiguration();
this.mappedStatement = mappedStatement;
this.rowBounds = rowBounds;
this.parameterHandler = parameterHandler;
this.boundSql = boundSql;
this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
this.objectFactory = configuration.getObjectFactory();
this.resultHandler = resultHandler;
}
//
// HANDLE OUTPUT PARAMETER
//
public void handleOutputParameters(CallableStatement cs) throws SQLException {
final Object parameterObject = parameterHandler.getParameterObject();
final MetaObject metaParam = configuration.newMetaObject(parameterObject);
final List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
for (int i = 0; i < parameterMappings.size(); i++) {
final ParameterMapping parameterMapping = parameterMappings.get(i);
if (parameterMapping.getMode() == ParameterMode.OUT || parameterMapping.getMode() == ParameterMode.INOUT) {
if (ResultSet.class.equals(parameterMapping.getJavaType())) {
handleRefCursorOutputParameter((ResultSet) cs.getObject(i + 1), parameterMapping, metaParam);
} else {
final TypeHandler<?> typeHandler = parameterMapping.getTypeHandler();
metaParam.setValue(parameterMapping.getProperty(), typeHandler.getResult(cs, i + 1));
}
}
}
}
private void handleRefCursorOutputParameter(ResultSet rs, ParameterMapping parameterMapping, MetaObject metaParam) throws SQLException {
try {
final String resultMapId = parameterMapping.getResultMapId();
final ResultMap resultMap = configuration.getResultMap(resultMapId);
final DefaultResultHandler resultHandler = new DefaultResultHandler(objectFactory);
final ResultSetWrapper rsw = new ResultSetWrapper(rs, configuration);
handleRowValues(rsw, resultMap, resultHandler, new RowBounds(), null);
metaParam.setValue(parameterMapping.getProperty(), resultHandler.getResultList());
} finally {
closeResultSet(rs); // issue #228 (close resultsets)
}
}
//
// HANDLE RESULT SETS
//
public List<Object> handleResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
final List<Object> multipleResults = new ArrayList<Object>();
int resultSetCount = 0;
ResultSetWrapper rsw = getFirstResultSet(stmt);
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
validateResultMapsCount(rsw, resultMapCount);
while (rsw != null && resultMapCount > resultSetCount) {
ResultMap resultMap = resultMaps.get(resultSetCount);
handleResultSet(rsw, resultMap, multipleResults, null);
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
String[] resultSets = mappedStatement.getResulSets();
if (resultSets != null) {
while (rsw != null && resultSetCount < resultSets.length) {
ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
if (parentMapping != null) {
String nestedResultMapId = parentMapping.getNestedResultMapId();
ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
handleResultSet(rsw, resultMap, null, parentMapping);
}
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
}
return collapseSingleResultList(multipleResults);
}
private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException {
ResultSet rs = stmt.getResultSet();
while (rs == null) {
// move forward to get the first resultset in case the driver
// doesn't return the resultset as the first result (HSQLDB 2.1)
if (stmt.getMoreResults()) {
rs = stmt.getResultSet();
} else {
if (stmt.getUpdateCount() == -1) {
// no more results. Must be no resultset
break;
}
}
}
return rs != null ? new ResultSetWrapper(rs, configuration) : null;
}
private ResultSetWrapper getNextResultSet(Statement stmt) throws SQLException {
// Making this method tolerant of bad JDBC drivers
try {
if (stmt.getConnection().getMetaData().supportsMultipleResultSets()) {
// Crazy Standard JDBC way of determining if there are more results
if (!((!stmt.getMoreResults()) && (stmt.getUpdateCount() == -1))) {
ResultSet rs = stmt.getResultSet();
return rs != null ? new ResultSetWrapper(rs, configuration) : null;
}
}
} catch (Exception e) {
// Intentionally ignored.
}
return null;
}
private void closeResultSet(ResultSet rs) {
try {
if (rs != null) {
rs.close();
}
} catch (SQLException e) {
// ignore
}
}
private void cleanUpAfterHandlingResultSet() {
nestedResultObjects.clear();
ancestorColumnPrefix.clear();
}
private void validateResultMapsCount(ResultSetWrapper rsw, int resultMapCount) {
if (rsw != null && resultMapCount < 1) {
throw new ExecutorException("A query was run and no Result Maps were found for the Mapped Statement '" + mappedStatement.getId()
+ "'. It's likely that neither a Result Type nor a Result Map was specified.");
}
}
private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
try {
if (parentMapping != null) {
handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
} else {
if (resultHandler == null) {
DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
multipleResults.add(defaultResultHandler.getResultList());
} else {
handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
}
}
} finally {
closeResultSet(rsw.getResultSet()); // issue #228 (close resultsets)
}
}
private List<Object> collapseSingleResultList(List<Object> multipleResults) {
if (multipleResults.size() == 1) {
@SuppressWarnings("unchecked")
List<Object> returned = (List<Object>) multipleResults.get(0);
return returned;
}
return multipleResults;
}
//
// HANDLE ROWS FOR SIMPLE RESULTMAP
//
private void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
if (resultMap.hasNestedResultMaps()) {
ensureNoRowBounds();
checkResultHandler();
handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
} else {
handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
}
}
private void ensureNoRowBounds() {
if (configuration.isSafeRowBoundsEnabled() && rowBounds != null && (rowBounds.getLimit() < RowBounds.NO_ROW_LIMIT || rowBounds.getOffset() > RowBounds.NO_ROW_OFFSET)) {
throw new ExecutorException("Mapped Statements with nested result mappings cannot be safely constrained by RowBounds. "
+ "Use safeRowBoundsEnabled=false setting to bypass this check.");
}
}
protected void checkResultHandler() {
if (resultHandler != null && configuration.isSafeResultHandlerEnabled() && !mappedStatement.isResultOrdered()) {
throw new ExecutorException("Mapped Statements with nested result mappings cannot be safely used with a custom ResultHandler. "
+ "Use safeResultHandlerEnabled=false setting to bypass this check "
+ "or ensure your statement returns ordered data and set resultOrdered=true on it.");
}
}
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
throws SQLException {
DefaultResultContext resultContext = new DefaultResultContext();
skipRows(rsw.getResultSet(), rowBounds);
while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
Object rowValue = getRowValue(rsw, discriminatedResultMap);
storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
}
}
private void storeObject(ResultHandler resultHandler, DefaultResultContext resultContext, Object rowValue, ResultMapping parentMapping, ResultSet rs) throws SQLException {
if (parentMapping != null) {
linkToParents(rs, parentMapping, rowValue);
} else {
callResultHandler(resultHandler, resultContext, rowValue);
}
}
private void callResultHandler(ResultHandler resultHandler, DefaultResultContext resultContext, Object rowValue) {
resultContext.nextResultObject(rowValue);
resultHandler.handleResult(resultContext);
}
private boolean shouldProcessMoreRows(ResultContext context, RowBounds rowBounds) throws SQLException {
return !context.isStopped() && context.getResultCount() < rowBounds.getLimit();
}
private void skipRows(ResultSet rs, RowBounds rowBounds) throws SQLException {
if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) {
if (rowBounds.getOffset() != RowBounds.NO_ROW_OFFSET) {
rs.absolute(rowBounds.getOffset());
}
} else {
for (int i = 0; i < rowBounds.getOffset(); i++) {
rs.next();
}
}
}
//
// GET VALUE FROM ROW FOR SIMPLE RESULT MAP
//
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {
final ResultLoaderMap lazyLoader = new ResultLoaderMap();
Object resultObject = createResultObject(rsw, resultMap, lazyLoader, null);
if (resultObject != null && !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) {
final MetaObject metaObject = configuration.newMetaObject(resultObject);
boolean foundValues = resultMap.getConstructorResultMappings().size() > 0;
if (shouldApplyAutomaticMappings(resultMap, !AutoMappingBehavior.NONE.equals(configuration.getAutoMappingBehavior()))) {
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;
}
foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;
foundValues = lazyLoader.size() > 0 || foundValues;
resultObject = foundValues ? resultObject : null;
return resultObject;
}
return resultObject;
}
private boolean shouldApplyAutomaticMappings(ResultMap resultMap, boolean def) {
return resultMap.getAutoMapping() != null ? resultMap.getAutoMapping() : def;
}
//
// PROPERTY MAPPINGS
//
private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, ResultLoaderMap lazyLoader, String columnPrefix)
throws SQLException {
final List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
boolean foundValues = false;
final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
for (ResultMapping propertyMapping : propertyMappings) {
final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
if (propertyMapping.isCompositeResult()
|| (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH)))
|| propertyMapping.getResultSet() != null) {
Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix);
final String property = propertyMapping.getProperty(); // issue #541 make property optional
if (value != NO_VALUE && property != null && (value != null || configuration.isCallSettersOnNulls())) { // issue #377, call setter on nulls
if (value != null || !metaObject.getSetterType(property).isPrimitive()) {
metaObject.setValue(property, value);
}
foundValues = true;
}
}
}
return foundValues;
}
private Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix)
throws SQLException {
if (propertyMapping.getNestedQueryId() != null) {
return getNestedQueryMappingValue(rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix);
} else if (propertyMapping.getResultSet() != null) {
addPendingChildRelation(rs, metaResultObject, propertyMapping);
return NO_VALUE;
} else if (propertyMapping.getNestedResultMapId() != null) {
// the user added a column attribute to a nested result map, ignore it
return NO_VALUE;
} else {
final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();
final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
return typeHandler.getResult(rs, column);
}
}
private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
final List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
boolean foundValues = false;
for (String columnName : unmappedColumnNames) {
String propertyName = columnName;
if (columnPrefix != null && columnPrefix.length() > 0) {
// When columnPrefix is specified,
// ignore columns without the prefix.
if (columnName.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {
propertyName = columnName.substring(columnPrefix.length());
} else {
continue;
}
}
final String property = metaObject.findProperty(propertyName, configuration.isMapUnderscoreToCamelCase());
if (property != null && metaObject.hasSetter(property)) {
final Class<?> propertyType = metaObject.getSetterType(property);
if (typeHandlerRegistry.hasTypeHandler(propertyType)) {
final TypeHandler<?> typeHandler = rsw.getTypeHandler(propertyType, columnName);
final Object value = typeHandler.getResult(rsw.getResultSet(), columnName);
if (value != null || configuration.isCallSettersOnNulls()) { // issue #377, call setter on nulls
if (value != null || !propertyType.isPrimitive()) {
metaObject.setValue(property, value);
}
foundValues = true;
}
}
}
}
return foundValues;
}
// MULTIPLE RESULT SETS
private void linkToParents(ResultSet rs, ResultMapping parentMapping, Object rowValue) throws SQLException {
CacheKey parentKey = createKeyForMultipleResults(rs, parentMapping, parentMapping.getColumn(), parentMapping.getForeignColumn());
List<PendingRelation> parents = pendingRelations.get(parentKey);
for (PendingRelation parent : parents) {
if (parent != null) {
final Object collectionProperty = instantiateCollectionPropertyIfAppropriate(parent.propertyMapping, parent.metaObject);
if (rowValue != null) {
if (collectionProperty != null) {
final MetaObject targetMetaObject = configuration.newMetaObject(collectionProperty);
targetMetaObject.add(rowValue);
} else {
parent.metaObject.setValue(parent.propertyMapping.getProperty(), rowValue);
}
}
}
}
}
private Object instantiateCollectionPropertyIfAppropriate(ResultMapping resultMapping, MetaObject metaObject) {
final String propertyName = resultMapping.getProperty();
Object propertyValue = metaObject.getValue(propertyName);
if (propertyValue == null) {
Class<?> type = resultMapping.getJavaType();
if (type == null) {
type = metaObject.getSetterType(propertyName);
}
try {
if (objectFactory.isCollection(type)) {
propertyValue = objectFactory.create(type);
metaObject.setValue(propertyName, propertyValue);
return propertyValue;
}
} catch (Exception e) {
throw new ExecutorException("Error instantiating collection property for result '" + resultMapping.getProperty() + "'. Cause: " + e, e);
}
} else if (objectFactory.isCollection(propertyValue.getClass())) {
return propertyValue;
}
return null;
}
private void addPendingChildRelation(ResultSet rs, MetaObject metaResultObject, ResultMapping parentMapping) throws SQLException {
CacheKey cacheKey = createKeyForMultipleResults(rs, parentMapping, parentMapping.getColumn(), parentMapping.getColumn());
PendingRelation deferLoad = new PendingRelation();
deferLoad.metaObject = metaResultObject;
deferLoad.propertyMapping = parentMapping;
List<PendingRelation> relations = pendingRelations.get(cacheKey);
// issue #255
if (relations == null) {
relations = new ArrayList<DefaultResultSetHandler.PendingRelation>();
pendingRelations.put(cacheKey, relations);
}
relations.add(deferLoad);
ResultMapping previous = nextResultMaps.get(parentMapping.getResultSet());
if (previous == null) {
nextResultMaps.put(parentMapping.getResultSet(), parentMapping);
} else {
if (!previous.equals(parentMapping)) {
throw new ExecutorException("Two different properties are mapped to the same resultSet");
}
}
}
private CacheKey createKeyForMultipleResults(ResultSet rs, ResultMapping resultMapping, String names, String columns) throws SQLException {
CacheKey cacheKey = new CacheKey();
cacheKey.update(resultMapping);
if (columns != null && names != null) {
String[] columnsArray = columns.split(",");
String[] namesArray = names.split(",");
for (int i = 0 ; i < columnsArray.length ; i++) {
Object value = rs.getString(columnsArray[i]);
if (value != null) {
cacheKey.update(namesArray[i]);
cacheKey.update(value);
}
}
}
return cacheKey;
}
//
// INSTANTIATION & CONSTRUCTOR MAPPING
//
private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
final List<Class<?>> constructorArgTypes = new ArrayList<Class<?>>();
final List<Object> constructorArgs = new ArrayList<Object>();
final Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);
if (resultObject != null && !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) {
final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
for (ResultMapping propertyMapping : propertyMappings) {
if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) { // issue gcode #109 && issue #149
return configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);
}
}
}
return resultObject;
}
private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix)
throws SQLException {
final Class<?> resultType = resultMap.getType();
final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
if (typeHandlerRegistry.hasTypeHandler(resultType)) {
return createPrimitiveResultObject(rsw, resultMap, columnPrefix);
} else if (constructorMappings.size() > 0) {
return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes, constructorArgs, columnPrefix);
} else {
return objectFactory.create(resultType);
}
}
private Object createParameterizedResultObject(ResultSetWrapper rsw, Class<?> resultType, List<ResultMapping> constructorMappings, List<Class<?>> constructorArgTypes,
List<Object> constructorArgs, String columnPrefix) throws SQLException {
boolean foundValues = false;
for (ResultMapping constructorMapping : constructorMappings) {
final Class<?> parameterType = constructorMapping.getJavaType();
final String column = constructorMapping.getColumn();
final Object value;
if (constructorMapping.getNestedQueryId() != null) {
value = getNestedQueryConstructorValue(rsw.getResultSet(), constructorMapping, columnPrefix);
} else if (constructorMapping.getNestedResultMapId() != null) {
final ResultMap resultMap = configuration.getResultMap(constructorMapping.getNestedResultMapId());
value = getRowValue(rsw, resultMap);
} else {
final TypeHandler<?> typeHandler = constructorMapping.getTypeHandler();
value = typeHandler.getResult(rsw.getResultSet(), prependPrefix(column, columnPrefix));
}
constructorArgTypes.add(parameterType);
constructorArgs.add(value);
foundValues = value != null || foundValues;
}
return foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null;
}
private Object createPrimitiveResultObject(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
final Class<?> resultType = resultMap.getType();
final String columnName;
if (resultMap.getResultMappings().size() > 0) {
final List<ResultMapping> resultMappingList = resultMap.getResultMappings();
final ResultMapping mapping = resultMappingList.get(0);
columnName = prependPrefix(mapping.getColumn(), columnPrefix);
} else {
columnName = rsw.getColumnNames().get(0);
}
final TypeHandler<?> typeHandler = rsw.getTypeHandler(resultType, columnName);
return typeHandler.getResult(rsw.getResultSet(), columnName);
}
//
// NESTED QUERY
//
private Object getNestedQueryConstructorValue(ResultSet rs, ResultMapping constructorMapping, String columnPrefix) throws SQLException {
final String nestedQueryId = constructorMapping.getNestedQueryId();
final MappedStatement nestedQuery = configuration.getMappedStatement(nestedQueryId);
final Class<?> nestedQueryParameterType = nestedQuery.getParameterMap().getType();
final Object nestedQueryParameterObject = prepareParameterForNestedQuery(rs, constructorMapping, nestedQueryParameterType, columnPrefix);
Object value = null;
if (nestedQueryParameterObject != null) {
final BoundSql nestedBoundSql = nestedQuery.getBoundSql(nestedQueryParameterObject);
final CacheKey key = executor.createCacheKey(nestedQuery, nestedQueryParameterObject, RowBounds.DEFAULT, nestedBoundSql);
final Class<?> targetType = constructorMapping.getJavaType();
final ResultLoader resultLoader = new ResultLoader(configuration, executor, nestedQuery, nestedQueryParameterObject, targetType, key, nestedBoundSql);
value = resultLoader.loadResult();
}
return value;
}
private Object getNestedQueryMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix)
throws SQLException {
final String nestedQueryId = propertyMapping.getNestedQueryId();
final String property = propertyMapping.getProperty();
final MappedStatement nestedQuery = configuration.getMappedStatement(nestedQueryId);
final Class<?> nestedQueryParameterType = nestedQuery.getParameterMap().getType();
final Object nestedQueryParameterObject = prepareParameterForNestedQuery(rs, propertyMapping, nestedQueryParameterType, columnPrefix);
Object value = NO_VALUE;
if (nestedQueryParameterObject != null) {
final BoundSql nestedBoundSql = nestedQuery.getBoundSql(nestedQueryParameterObject);
final CacheKey key = executor.createCacheKey(nestedQuery, nestedQueryParameterObject, RowBounds.DEFAULT, nestedBoundSql);
final Class<?> targetType = propertyMapping.getJavaType();
if (executor.isCached(nestedQuery, key)) {
executor.deferLoad(nestedQuery, metaResultObject, property, key, targetType);
} else {
final ResultLoader resultLoader = new ResultLoader(configuration, executor, nestedQuery, nestedQueryParameterObject, targetType, key, nestedBoundSql);
if (propertyMapping.isLazy()) {
lazyLoader.addLoader(property, metaResultObject, resultLoader);
} else {
value = resultLoader.loadResult();
}
}
}
return value;
}
private Object prepareParameterForNestedQuery(ResultSet rs, ResultMapping resultMapping, Class<?> parameterType, String columnPrefix) throws SQLException {
if (resultMapping.isCompositeResult()) {
return prepareCompositeKeyParameter(rs, resultMapping, parameterType, columnPrefix);
} else {
return prepareSimpleKeyParameter(rs, resultMapping, parameterType, columnPrefix);
}
}
private Object prepareSimpleKeyParameter(ResultSet rs, ResultMapping resultMapping, Class<?> parameterType, String columnPrefix) throws SQLException {
final TypeHandler<?> typeHandler;
if (typeHandlerRegistry.hasTypeHandler(parameterType)) {
typeHandler = typeHandlerRegistry.getTypeHandler(parameterType);
} else {
typeHandler = typeHandlerRegistry.getUnknownTypeHandler();
}
return typeHandler.getResult(rs, prependPrefix(resultMapping.getColumn(), columnPrefix));
}
private Object prepareCompositeKeyParameter(ResultSet rs, ResultMapping resultMapping, Class<?> parameterType, String columnPrefix) throws SQLException {
final Object parameterObject = instantiateParameterObject(parameterType);
final MetaObject metaObject = configuration.newMetaObject(parameterObject);
boolean foundValues = false;
for (ResultMapping innerResultMapping : resultMapping.getComposites()) {
final Class<?> propType = metaObject.getSetterType(innerResultMapping.getProperty());
final TypeHandler<?> typeHandler = typeHandlerRegistry.getTypeHandler(propType);
final Object propValue = typeHandler.getResult(rs, prependPrefix(innerResultMapping.getColumn(), columnPrefix));
if (propValue != null) { // issue #353 & #560 do not execute nested query if key is null
metaObject.setValue(innerResultMapping.getProperty(), propValue);
foundValues = true;
}
}
return foundValues ? parameterObject : null;
}
private Object instantiateParameterObject(Class<?> parameterType) {
if (parameterType == null) {
return new HashMap<Object, Object>();
} else {
return objectFactory.create(parameterType);
}
}
//
// DISCRIMINATOR
//
public ResultMap resolveDiscriminatedResultMap(ResultSet rs, ResultMap resultMap, String columnPrefix) throws SQLException {
Set<String> pastDiscriminators = new HashSet<String>();
Discriminator discriminator = resultMap.getDiscriminator();
while (discriminator != null) {
final Object value = getDiscriminatorValue(rs, discriminator, columnPrefix);
final String discriminatedMapId = discriminator.getMapIdFor(String.valueOf(value));
if (configuration.hasResultMap(discriminatedMapId)) {
resultMap = configuration.getResultMap(discriminatedMapId);
Discriminator lastDiscriminator = discriminator;
discriminator = resultMap.getDiscriminator();
if (discriminator == lastDiscriminator || !pastDiscriminators.add(discriminatedMapId)) {
break;
}
} else {
break;
}
}
return resultMap;
}
private Object getDiscriminatorValue(ResultSet rs, Discriminator discriminator, String columnPrefix) throws SQLException {
final ResultMapping resultMapping = discriminator.getResultMapping();
final TypeHandler<?> typeHandler = resultMapping.getTypeHandler();
return typeHandler.getResult(rs, prependPrefix(resultMapping.getColumn(), columnPrefix));
}
private String prependPrefix(String columnName, String prefix) {
if (columnName == null || columnName.length() == 0 || prefix == null || prefix.length() == 0) {
return columnName;
}
return prefix + columnName;
}
//
// HANDLE NESTED RESULT MAPS
//
private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
final DefaultResultContext resultContext = new DefaultResultContext();
skipRows(rsw.getResultSet(), rowBounds);
Object rowValue = null;
while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
final ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
final CacheKey rowKey = createRowKey(discriminatedResultMap, rsw, null);
Object partialObject = nestedResultObjects.get(rowKey);
if (mappedStatement.isResultOrdered()) { // issue #577 && #542
if (partialObject == null && rowValue != null) {
nestedResultObjects.clear();
storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
}
rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, rowKey, null, partialObject);
} else {
rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, rowKey, null, partialObject);
if (partialObject == null) {
storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
}
}
}
if (rowValue != null && mappedStatement.isResultOrdered() && shouldProcessMoreRows(resultContext, rowBounds)) {
storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
}
}
//
// GET VALUE FROM ROW FOR NESTED RESULT MAP
//
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, CacheKey combinedKey, CacheKey absoluteKey, String columnPrefix, Object partialObject) throws SQLException {
final String resultMapId = resultMap.getId();
Object resultObject = partialObject;
if (resultObject != null) {
final MetaObject metaObject = configuration.newMetaObject(resultObject);
putAncestor(absoluteKey, resultObject, resultMapId, columnPrefix);
applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, false);
ancestorObjects.remove(absoluteKey);
} else {
final ResultLoaderMap lazyLoader = new ResultLoaderMap();
resultObject = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
if (resultObject != null && !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) {
final MetaObject metaObject = configuration.newMetaObject(resultObject);
boolean foundValues = resultMap.getConstructorResultMappings().size() > 0;
if (shouldApplyAutomaticMappings(resultMap, AutoMappingBehavior.FULL.equals(configuration.getAutoMappingBehavior()))) {
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
}
foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
putAncestor(absoluteKey, resultObject, resultMapId, columnPrefix);
foundValues = applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, true) || foundValues;
ancestorObjects.remove(absoluteKey);
foundValues = lazyLoader.size() > 0 || foundValues;
resultObject = foundValues ? resultObject : null;
}
if (combinedKey != CacheKey.NULL_CACHE_KEY) nestedResultObjects.put(combinedKey, resultObject);
}
return resultObject;
}
private void putAncestor(CacheKey rowKey, Object resultObject, String resultMapId, String columnPrefix) {
if (!ancestorColumnPrefix.containsKey(resultMapId)) {
ancestorColumnPrefix.put(resultMapId, columnPrefix);
}
ancestorObjects.put(rowKey, resultObject);
}
//
// NESTED RESULT MAP (JOIN MAPPING)
//
private boolean applyNestedResultMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String parentPrefix, CacheKey parentRowKey, boolean newObject) {
boolean foundValues = false;
for (ResultMapping resultMapping : resultMap.getPropertyResultMappings()) {
final String nestedResultMapId = resultMapping.getNestedResultMapId();
if (nestedResultMapId != null && resultMapping.getResultSet() == null) {
try {
final String columnPrefix = getColumnPrefix(parentPrefix, resultMapping);
final ResultMap nestedResultMap = getNestedResultMap(rsw.getResultSet(), nestedResultMapId, columnPrefix);
CacheKey rowKey = null;
Object ancestorObject = null;
if (ancestorColumnPrefix.containsKey(nestedResultMapId)) {
rowKey = createRowKey(nestedResultMap, rsw, ancestorColumnPrefix.get(nestedResultMapId));
ancestorObject = ancestorObjects.get(rowKey);
}
if (ancestorObject != null) {
if (newObject) metaObject.setValue(resultMapping.getProperty(), ancestorObject);
} else {
rowKey = createRowKey(nestedResultMap, rsw, columnPrefix);
final CacheKey combinedKey = combineKeys(rowKey, parentRowKey);
Object rowValue = nestedResultObjects.get(combinedKey);
boolean knownValue = (rowValue != null);
final Object collectionProperty = instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject);
if (anyNotNullColumnHasValue(resultMapping, columnPrefix, rsw.getResultSet())) {
rowValue = getRowValue(rsw, nestedResultMap, combinedKey, rowKey, columnPrefix, rowValue);
if (rowValue != null && !knownValue) {
if (collectionProperty != null) {
final MetaObject targetMetaObject = configuration.newMetaObject(collectionProperty);
targetMetaObject.add(rowValue);
} else {
metaObject.setValue(resultMapping.getProperty(), rowValue);
}
foundValues = true;
}
}
}
} catch (SQLException e) {
throw new ExecutorException("Error getting nested result map values for '" + resultMapping.getProperty() + "'. Cause: " + e, e);
}
}
}
return foundValues;
}
private String getColumnPrefix(String parentPrefix, ResultMapping resultMapping) {
final StringBuilder columnPrefixBuilder = new StringBuilder();
if (parentPrefix != null) columnPrefixBuilder.append(parentPrefix);
if (resultMapping.getColumnPrefix() != null) columnPrefixBuilder.append(resultMapping.getColumnPrefix());
final String columnPrefix = columnPrefixBuilder.length() == 0 ? null : columnPrefixBuilder.toString().toUpperCase(Locale.ENGLISH);
return columnPrefix;
}
private boolean anyNotNullColumnHasValue(ResultMapping resultMapping, String columnPrefix, ResultSet rs) throws SQLException {
Set<String> notNullColumns = resultMapping.getNotNullColumns();
boolean anyNotNullColumnHasValue = true;
if (notNullColumns != null && !notNullColumns.isEmpty()) {
anyNotNullColumnHasValue = false;
for (String column: notNullColumns) {
rs.getObject(prependPrefix(column, columnPrefix));
if (!rs.wasNull()) {
anyNotNullColumnHasValue = true;
break;
}
}
}
return anyNotNullColumnHasValue;
}
private ResultMap getNestedResultMap(ResultSet rs, String nestedResultMapId, String columnPrefix) throws SQLException {
ResultMap nestedResultMap = configuration.getResultMap(nestedResultMapId);
nestedResultMap = resolveDiscriminatedResultMap(rs, nestedResultMap, columnPrefix);
return nestedResultMap;
}
//
// UNIQUE RESULT KEY
//
private CacheKey createRowKey(ResultMap resultMap, ResultSetWrapper rsw, String columnPrefix) throws SQLException {
final CacheKey cacheKey = new CacheKey();
cacheKey.update(resultMap.getId());
List<ResultMapping> resultMappings = getResultMappingsForRowKey(resultMap);
if (resultMappings.size() == 0) {
if (Map.class.isAssignableFrom(resultMap.getType())) {
createRowKeyForMap(rsw, cacheKey);
} else {
createRowKeyForUnmappedProperties(resultMap, rsw, cacheKey, columnPrefix);
}
} else {
createRowKeyForMappedProperties(resultMap, rsw, cacheKey, resultMappings, columnPrefix);
}
return cacheKey;
}
private CacheKey combineKeys(CacheKey rowKey, CacheKey parentRowKey) {
if (rowKey.getUpdateCount() > 1 && parentRowKey.getUpdateCount() > 1) {
CacheKey combinedKey;
try {
combinedKey = rowKey.clone();
} catch (CloneNotSupportedException e) {
throw new ExecutorException("Error cloning cache key. Cause: " + e, e);
}
combinedKey.update(parentRowKey);
return combinedKey;
}
return CacheKey.NULL_CACHE_KEY;
}
private List<ResultMapping> getResultMappingsForRowKey(ResultMap resultMap) {
List<ResultMapping> resultMappings = resultMap.getIdResultMappings();
if (resultMappings.size() == 0) {
resultMappings = resultMap.getPropertyResultMappings();
}
return resultMappings;
}
private void createRowKeyForMappedProperties(ResultMap resultMap, ResultSetWrapper rsw, CacheKey cacheKey, List<ResultMapping> resultMappings, String columnPrefix) throws SQLException {
for (ResultMapping resultMapping : resultMappings) {
if (resultMapping.getNestedResultMapId() != null && resultMapping.getResultSet() == null) { // Issue #392
final ResultMap nestedResultMap = configuration.getResultMap(resultMapping.getNestedResultMapId());
createRowKeyForMappedProperties(nestedResultMap, rsw, cacheKey, nestedResultMap.getConstructorResultMappings(),
prependPrefix(resultMapping.getColumnPrefix(), columnPrefix));
} else if (resultMapping.getNestedQueryId() == null) {
final String column = prependPrefix(resultMapping.getColumn(), columnPrefix);
final TypeHandler<?> th = resultMapping.getTypeHandler();
List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
if (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH))) { // Issue #114
final Object value = th.getResult(rsw.getResultSet(), column);
if (value != null) {
cacheKey.update(column);
cacheKey.update(value);
}
}
}
}
}
private void createRowKeyForUnmappedProperties(ResultMap resultMap, ResultSetWrapper rsw, CacheKey cacheKey, String columnPrefix) throws SQLException {
final MetaClass metaType = MetaClass.forClass(resultMap.getType());
List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
for (String column : unmappedColumnNames) {
String property = column;
if (columnPrefix != null && columnPrefix.length() > 0) {
// When columnPrefix is specified,
// ignore columns without the prefix.
if (column.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {
property = column.substring(columnPrefix.length());
} else {
continue;
}
}
if (metaType.findProperty(property, configuration.isMapUnderscoreToCamelCase()) != null) {
String value = rsw.getResultSet().getString(column);
if (value != null) {
cacheKey.update(column);
cacheKey.update(value);
}
}
}
}
private void createRowKeyForMap(ResultSetWrapper rsw, CacheKey cacheKey) throws SQLException {
List<String> columnNames = rsw.getColumnNames();
for (String columnName : columnNames) {
final String value = rsw.getResultSet().getString(columnName);
if (value != null) {
cacheKey.update(columnName);
cacheKey.update(value);
}
}
}
}