HelloWorld 源码全流程
SqlSessionFactory 的初始化
SqlSessionFactoryBuilder
public SqlSessionFactory build(InputStream inputStream
, String environment, Properties properties) {
try {
// 创建解析器
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
// ===== ↓↓↓ Step Into ↓↓↓ =====
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
XMLConfigBuilder
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
// ===== ↓↓↓ Step Into ↓↓↓ =====
parseConfiguration(parser.evalNode("/configuration")); // 根节点
return configuration;
}
private void parseConfiguration(XNode root) {
// 挨个解析<configuration>下的每一个子节点,将详细信息保存在 configuration 中
try {
Properties settings = settingsAsPropertiess(root.evalNode("settings"));
//issue #117 read properties first
propertiesElement(root.evalNode("properties"));
loadCustomVfs(settings);
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectorFactoryElement(root.evalNode("reflectorFactory"));
// ===== ↓↓↓ Step Into ↓↓↓ =====
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
environmentsElement(root.evalNode("environments"));
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
typeHandlerElement(root.evalNode("typeHandlers"));
// ===== ↓↓↓ Step Into ↓↓↓ =====
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
// props ←→ <settings>
private void settingsElement(Properties props) throws Exception {
configuration.setAutoMappingBehavior(AutoMappingBehavior
.valueOf(props.getProperty("autoMappingBehavior", "PARTIAL")));
configuration.setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior
.valueOf(props.getProperty("autoMappingUnknownColumnBehavior", "NONE")));
configuration.setCacheEnabled(
booleanValueOf(props.getProperty("cacheEnabled"), true));
configuration.setProxyFactory(
(ProxyFactory) createInstance(props.getProperty("proxyFactory")));
configuration.setLazyLoadingEnabled(booleanValueOf(
props.getProperty("lazyLoadingEnabled"), false));
configuration.setAggressiveLazyLoading(
booleanValueOf(props.getProperty("aggressiveLazyLoading"), true));
configuration.setMultipleResultSetsEnabled(
booleanValueOf(props.getProperty("multipleResultSetsEnabled"), true));
configuration.setUseColumnLabel(
booleanValueOf(props.getProperty("useColumnLabel"), true));
configuration.setUseGeneratedKeys(
booleanValueOf(props.getProperty("useGeneratedKeys"), false));
configuration.setDefaultExecutorType(
ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));
configuration.setDefaultStatementTimeout(
integerValueOf(props.getProperty("defaultStatementTimeout"), null));
configuration.setDefaultFetchSize(
integerValueOf(props.getProperty("defaultFetchSize"), null));
configuration.setMapUnderscoreToCamelCase(
booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false));
configuration.setSafeRowBoundsEnabled(
booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false));
configuration.setLocalCacheScope(
LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION")));
configuration.setJdbcTypeForNull(
JdbcType.valueOf(props.getProperty("jdbcTypeForNull", "OTHER")));
configuration.setLazyLoadTriggerMethods(stringSetValueOf(
props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString"));
configuration.setSafeResultHandlerEnabled(
booleanValueOf(props.getProperty("safeResultHandlerEnabled"), true));
configuration.setDefaultScriptingLanguage(
resolveClass(props.getProperty("defaultScriptingLanguage")));
configuration.setCallSettersOnNulls(
booleanValueOf(props.getProperty("callSettersOnNulls"), false));
configuration.setUseActualParamName(
booleanValueOf(props.getProperty("useActualParamName"), false));
configuration.setLogPrefix(props.getProperty("logPrefix"));
@SuppressWarnings("unchecked")
Class<? extends Log> logImpl =
(Class<? extends Log>)resolveClass(props.getProperty("logImpl"));
configuration.setLogImpl(logImpl);
configuration.setConfigurationFactory(
resolveClass(props.getProperty("configurationFactory")));
}
private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
if ("package".equals(child.getName())) {
String mapperPackage = child.getStringAttribute("name");
configuration.addMappers(mapperPackage);
} else {
String resource = child.getStringAttribute("resource");
String url = child.getStringAttribute("url");
String mapperClass = child.getStringAttribute("class");
if (resource != null && url == null && mapperClass == null) {
ErrorContext.instance().resource(resource);
InputStream inputStream = Resources.getResourceAsStream(resource);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(
inputStream, configuration, resource, configuration.getSqlFragments());
// ===== ↓↓↓ Step Into ↓↓↓ =====> #1.3
mapperParser.parse();
} else if (resource == null && url != null && mapperClass == null) {
ErrorContext.instance().resource(url);
InputStream inputStream = Resources.getUrlAsStream(url);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(
inputStream, configuration, url, configuration.getSqlFragments());
mapperParser.parse();
} else if (resource == null && url == null && mapperClass != null) {
Class<?> mapperInterface = Resources.classForName(mapperClass);
configuration.addMapper(mapperInterface);
} else {
throw new BuilderException("A mapper element may only specify a url"
+ ", resource or class, but not more than one.");
}
}
}
}
}
XMLMapperBuilder
private void configurationElement(XNode context) {
try {
String namespace = context.getStringAttribute("namespace");
if (namespace == null || namespace.equals("")) {
throw new BuilderException("Mapper's namespace cannot be empty");
}
builderAssistant.setCurrentNamespace(namespace);
cacheRefElement(context.evalNode("cache-ref"));
cacheElement(context.evalNode("cache"));
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
resultMapElements(context.evalNodes("/mapper/resultMap"));
// 可重用 SQL
sqlElement(context.evalNodes("/mapper/sql"));
// ===== ↓↓↓ Step Into ↓↓↓ =====
buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
} catch (Exception e) {
throw new BuilderException("Error parsing Mapper XML. Cause: " + e, e);
}
}
private void buildStatementFromContext(List<XNode> list) {
if (configuration.getDatabaseId() != null) {
buildStatementFromContext(list, configuration.getDatabaseId());
}
// ===== ↓↓↓ Step Into ↓↓↓ =====
buildStatementFromContext(list, null);
}
private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
for (XNode context : list) {
// 解析 CRUD 标签的解析器
final XMLStatementBuilder statementParser = new XMLStatementBuilder(
configuration, builderAssistant, context, requiredDatabaseId);
try {
// ===== ↓↓↓ Step Into ↓↓↓ =====> #1.4
statementParser.parseStatementNode();
} catch (IncompleteElementException e) {
configuration.addIncompleteStatement(statementParser);
}
}
}
XMLStatementBuilder
public void parseStatementNode() {
// 将 CRUD 标签中的一个个属性都解析出来 ...
// ===== ↓↓↓ Step Into ↓↓↓ =====
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType
, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap
, resultTypeClass, resultSetTypeEnum, flushCache, useCache, resultOrdered
, keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}
MapperBuilderAssistant
public MappedStatement addMappedStatement(对应上一步的那一堆配置...) {
MappedStatement.Builder statementBuilder = new MappedStatement.Builder(
configuration, id, sqlSource, sqlCommandType).配置全部加进来;
ParameterMap statementParameterMap =
getStatementParameterMap(parameterMap, parameterType, id);
if (statementParameterMap != null) {
statementBuilder.parameterMap(statementParameterMap);
}
// 根据解析出来的配置,构建一个 MappedStatement 对象(封装一个 CRUD 标签的详细信息)
MappedStatement statement = statementBuilder.build();
// 把这个 MappedStatement 加入到 configuration 中
configuration.addMappedStatement(statement);
return statement;
}
Configuration
Configuration 对象保存了所有配置文件(全局、映射) 的详细信息。
获取 SqlSession
Mybatis 四大组件之一的 Executor 在这一步会被创建。
DefaultSqlSessionFactory
@Override
public SqlSession openSession(boolean autoCommit) {
// ===== ↓↓↓ Step Into ↓↓↓ =====
return openSessionFromDataSource(
configuration.getDefaultExecutorType(), null, autoCommit);
}
private SqlSession openSessionFromDataSource(ExecutorType execType
, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory
= getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
// ===== ↓↓↓ Step Into ↓↓↓ =====> 得先创建 Executor → #2.2
final Executor executor = configuration.newExecutor(tx, execType);
// Executor 作为 SqlSession 构造器形参之一,只有先有它才能创建 SqlSession → #2.5
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();
}
}
Configuration
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
// 根据 Executor 在全局配置文件中配置的类型,创建出相应的 XxxExecutor
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else { // SIMPLE
executor = new SimpleExecutor(this, transaction); // √
}
if (cacheEnabled) {
// ===== ↓↓↓ Step Into ↓↓↓ =====> 若配置了二级缓存 → #2.3
executor = new CachingExecutor(executor); // 包装 Executor
}
// ===== ↓↓↓ Step Into ↓↓↓ =====> 返回经拦截器们包装后的 Executor → #2.4
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
CachingExecutor
public class CachingExecutor implements Executor {
// 原始 Executor
private Executor delegate;
// 二级缓存
private TransactionalCacheManager tcm = new TransactionalCacheManager();
// 对传进来的 Executor 做了包装,并返回包装后的 Executor
public CachingExecutor(Executor delegate) {
this.delegate = delegate;
delegate.setExecutorWrapper(this);
}
// ...
}
InterceptorChain
private final List<Interceptor> interceptors = new ArrayList<Interceptor>();
public Object pluginAll(Object target) {
// 每个拦截器都来重新包装 Executor
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
}
DefaultSqlSession
public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
this.configuration = configuration;
this.executor = executor;
this.dirty = false;
this.autoCommit = autoCommit;
}
返回 Mapper 代理对象
DefaultSqlSession
@Override
public <T> T getMapper(Class<T> type) {
// ===== ↓↓↓ Step Into ↓↓↓ =====
return configuration.<T>getMapper(type, this);
}
Configuration
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
// ===== ↓↓↓ Step Into ↓↓↓ =====
return mapperRegistry.getMapper(type, sqlSession);
}
MapperRegistry
@SuppressWarnings("unchecked")
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
// 根据 Mapper<I> 类型从这个 Map 中拿到对应的 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 {
// ===== ↓↓↓ Step Into ↓↓↓ =====> mapperProxyFactory 根据 sqlSession 创建 MapperProxy
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
MapperProxyFactory
public T newInstance(SqlSession sqlSession) {
// ===== ↓↓↓ Step Into ↓↓↓ =====> #3.5 → 创建 MapperProxy 对象
final MapperProxy<T> mapperProxy = new MapperProxy<T>(
sqlSession, mapperInterface, methodCache);
// ===== ↓↓↓ Step Into ↓↓↓ =====> 对上一步创建的 MapperProxy 对象做动态代理,并返回
return newInstance(mapperProxy);
}
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader()
, new Class[] { mapperInterface }, mapperProxy);
}
MapperProxy
public class MapperProxy<T> implements InvocationHandler, Serializable {
private static final long serialVersionUID = -6424540398559729838L;
private final SqlSession sqlSession;
private final Class<T> mapperInterface;
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;
}
}
调用查询方法
MapperProxy
@Override
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);
}
}
final MapperMethod mapperMethod = cachedMapperMethod(method);
// ===== ↓↓↓ Step Into ↓↓↓ =====> 传入 sqlSession 和方法参数
return mapperMethod.execute(sqlSession, args);
}
MapperMethod
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
switch (command.getType()) {
case INSERT: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
break;
}
case UPDATE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
break;
}
case DELETE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
break;
}
case SELECT:
if (method.returnsVoid() && method.hasResultHandler()) {
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
result = executeForMap(sqlSession, args);
} else if (method.returnsCursor()) {
result = executeForCursor(sqlSession, args);
} else {
// ===== ↓↓↓ Step Into ↓↓↓ =====> 封装参数 → 下面的方法
Object param = method.convertArgsToSqlCommandParam(args);
// ===== ↓↓↓ Step Into ↓↓↓ =====> #4.4
result = sqlSession.selectOne(command.getName(), param);
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
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;
}
public static class MethodSignature {
private final ParamNameResolver paramNameResolver;
public Object convertArgsToSqlCommandParam(Object[] args) {
// ===== ↓↓↓ Step Into ↓↓↓ =====> 调用参数解析器 → #4.3
return paramNameResolver.getNamedParams(args);
}
}
ParamNameResolver
private static final String GENERIC_NAME_PREFIX = "param";
public ParamNameResolver(Configuration config, Method method) {
final Class<?>[] paramTypes = method.getParameterTypes();
final Annotation[][] paramAnnotations = method.getParameterAnnotations();
final SortedMap<Integer, String> map = new TreeMap<Integer, String>();
int paramCount = paramAnnotations.length;
// get names from @Param annotations
for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) {
if (isSpecialParameter(paramTypes[paramIndex])) {
// skip special parameters
continue;
}
String name = null;
for (Annotation annotation : paramAnnotations[paramIndex]) {
if (annotation instanceof Param) {
hasParamAnnotation = true;
name = ((Param) annotation).value();
break;
}
}
if (name == null) {
// @Param was not specified.
if (config.isUseActualParamName()) {
name = getActualParamName(method, paramIndex);
}
if (name == null) {
// use the parameter index as the name ("0", "1", ...)
// gcode issue #71
name = String.valueOf(map.size());
}
}
map.put(paramIndex, name);
}
names = Collections.unmodifiableSortedMap(map);
}
public Object getNamedParams(Object[] args) {
final int paramCount = names.size();
if (args == null || paramCount == 0) {
return null;
} else if (!hasParamAnnotation && paramCount == 1) {
return args[names.firstKey()];
} else {
final Map<String, Object> param = new ParamMap<Object>();
int i = 0;
for (Map.Entry<Integer, String> entry : names.entrySet()) {
param.put(entry.getValue(), args[entry.getKey()]);
// add generic param names (param1, param2, ...)
final String genericParamName = GENERIC_NAME_PREFIX + String.valueOf(i + 1);
// ensure not to overwrite parameter named with @Param
if (!names.containsValue(genericParamName)) {
param.put(genericParamName, args[entry.getKey()]);
}
i++;
}
return param;
}
}
DefaultSqlSession
@Override
public <T> T selectOne(String statement, Object parameter) {
// Popular vote was to return null on 0 results and throw exception on too many.
// ===== ↓↓↓ Step Into ↓↓↓ =====
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;
}
}
@Override
public <E> List<E> selectList(String statement, Object parameter) {
// ===== ↓↓↓ Step Into ↓↓↓ =====
// statement: cn.edu.nuist.mapper.TeacherMapper.getTeacherByTid
return this.selectList(statement, parameter, RowBounds.DEFAULT);
}
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
// Configuration 成员:Map<String, MappedStatement> mappedStatements
// 根据该 statement(select标签的唯一标识),拿到了对应的 MappedStatement
// 该 MappedStatement 对象中封装了对应的 <select> 的详细信息
MappedStatement ms = configuration.getMappedStatement(statement);
// ===== ↓↓↓ Step Into ↓↓↓ =====> 先钻入下面的方法 → 然后是 #4.5
return executor.query(
ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
// 嘿!
private Object wrapCollection(final Object object) {
if (object instanceof Collection) {
StrictMap<Object> map = new StrictMap<Object>();
map.put("collection", object);
if (object instanceof List) {
map.put("list", object);
}
return map;
} else if (object != null && object.getClass().isArray()) {
StrictMap<Object> map = new StrictMap<Object>();
map.put("array", object);
return map;
}
return object;
}
CachingExecutor
@Override
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);
// ===== ↓↓↓ Step Into ↓↓↓ =====
return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
@Override
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")
// 先看二级缓存(TransactionalCacheManager) 中有没有
List<E> list = (List<E>) tcm.getObject(cache, key);
if (list == null) {
// ===== ↓↓↓ Step Into ↓↓↓ =====> #4.6
list = delegate.<E> query(
ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
CachingExecutor 是对 Executor 的包装,所以最终还是调用原始 Executor 的 query 方法。
BaseExecutor
@SuppressWarnings("unchecked")
@Override
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.");
}
if (queryStack == 0 && ms.isFlushCacheRequired()) {
clearLocalCache();
}
List<E> list;
try {
queryStack++;
// 拿 cacheKey 在一级缓存(localCache) 中查找!
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
if (list != null) {
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else { // 没找到就去 DB 中找
// ===== ↓↓↓ Step Into ↓↓↓ =====
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
queryStack--;
}
if (queryStack == 0) {
for (DeferredLoad deferredLoad : deferredLoads) {
deferredLoad.load();
}
// issue #601
deferredLoads.clear();
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
// issue #482
clearLocalCache();
}
}
return list;
}
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 {
// ===== ↓↓↓ Step Into ↓↓↓ =====> 4.7
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;
}
SimpleExecutor*
在此方法内创建了 StatementHandler (ParameterHandler、ResultSetHandler)
@Override
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();
// ===== ↓↓↓ Step Into ↓↓↓ =====> StatementHandler(可用来创建 Statement 对象) → #4.8
StatementHandler handler = configuration.newStatementHandler(
wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
// ===== ↓↓↓ Step Into ↓↓↓ =====> 创建 Statement 对象 → 就在下面 ~
stmt = prepareStatement(handler, ms.getStatementLog());
// ===== ↓↓↓ Step Into ↓↓↓ =====> #4.9[3]
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
private Statement prepareStatement(
StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
Connection connection = getConnection(statementLog);
stmt = handler.prepare(connection, transaction.getTimeout());
// ===== ↓↓↓ Step Into ↓↓↓ =====> #4.11
// 面上是 StatementHandler 调用的,实际是 ParameterHandler 来做的参数预编译
// ParameterHandler 创建时机:创建 StatementHandler 时一并创建的 → #4.10
handler.parameterize(stmt);
return stmt;
}
Configuration
public StatementHandler newStatementHandler(Executor executor
, MappedStatement mappedStatement, Object parameterObject
, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
// ===== ↓↓↓ Step Into ↓↓↓ =====> #4.9
StatementHandler statementHandler = new RoutingStatementHandler(executor
, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
// 使用拦截器包装 StatementHandler
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
public ParameterHandler newParameterHandler(
MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
ParameterHandler parameterHandler = mappedStatement.getLang()
.createParameterHandler(mappedStatement, parameterObject, boundSql);
parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
return parameterHandler;
}
public ResultSetHandler newResultSetHandler(Executor executor
, MappedStatement mappedStatement, RowBounds rowBounds
, ParameterHandler parameterHandler, ResultHandler
resultHandler, BoundSql boundSql) {
ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor,
mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
return resultSetHandler;
}
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
RoutingStatementHandler
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter
, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
switch (ms.getStatementType()) {
case STATEMENT:
delegate = new SimpleStatementHandler(executor
, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case PREPARED:
// ===== ↓↓↓ Step Into ↓↓↓ =====> { super(...); } → #4.10
delegate = new PreparedStatementHandler(executor
, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case CALLABLE:
delegate = new CallableStatementHandler(executor
, ms, parameter, rowBounds, resultHandler, boundSql);
break;
default:
throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
}
}
@Override
public void parameterize(Statement statement) throws SQLException {
delegate.parameterize(statement);
}
@Override
public <E> List<E> query(Statement statement
, ResultHandler resultHandler) throws SQLException {
// ===== ↓↓↓ Step Into ↓↓↓ =====> #4.11[2]
return delegate.<E>query(statement, resultHandler);
}
BaseStatementHandler
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
generateKeys(parameterObject);
boundSql = mappedStatement.getBoundSql(parameterObject);
}
this.boundSql = boundSql;
// ===== ↓↓↓ Step Into ↓↓↓ =====> 还会同时创建另外两个组件!!! → 组件创建: #4.8
this.parameterHandler = configuration.newParameterHandler(
mappedStatement, parameterObject, boundSql);
this.resultSetHandler = configuration.newResultSetHandler(executor
, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}
如果看到这了,现在再回到 #4.7!看第二个要 Step Into 的地方!
PreparedStatementHandler
@Override
public void parameterize(Statement statement) throws SQLException {
// ===== ↓↓↓ Step Into ↓↓↓ =====> #4.12
parameterHandler.setParameters((PreparedStatement) statement);
}
@Override
public <E> List<E> query(Statement statement
, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
// ===== ↓↓↓ Step Into ↓↓↓ =====> #4.13
return resultSetHandler.<E> handleResultSets(ps);
}
DefaultParameterHandler
@Override
public void setParameters(PreparedStatement ps) {
// ...
// TypeHandler 给 SQL 预编译设置参数
TypeHandler typeHandler = parameterMapping.getTypeHandler();
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) {
jdbcType = configuration.getJdbcTypeForNull();
}
typeHandler.setParameter(ps, i + 1, value, jdbcType);
// ...
}
回到 #4.7,继续走第 3 个断点。
DefaultResultSetHandler
JavaBean 和表记录的映射(设置参数、结果映射) 由 TypeHandler 完成。
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 DEFERED;
} else {
final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();
final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
return typeHandler.getResult(rs, column);
}
}
小结
总结
- 根据配置文件(全局、映射) 初始化出 Configuration 对象
- 创建一个 DefaultSqlSession 对象,其中包含 Configuration、Executor (根据全局配置文件中的 defaultExecutorType 创建出对应的 Executor) 对象的引用。
DefaultSqlSession.getMapper(class)
,首先拿到Mapper<I>
对应的 MapperProxyFactory,然后通过newInstance()
创建 MapperProxy 对象,最终返回的是该对象的动态代理。- 执行 CRUD 方法
- 底层是代理对象调用了 DefaultSqlSession 对象的 CRUD 方法
- 会创建一个 Statement 对象 (会首先创建 StatementHandler,而在 StatementHandler 的构造器中又会创建 ParameterHandler、ResultSetHandler 对象)
- 调用 StatementHandler 预编译参数以及设置参数值(底层实际是调用 ParameterHandler 来做的)
- 调用 StatementHandler 的 CRUD 方法
- 使用 ResultSetHandler 封装结果
【注意】MyBatis 的四大组件创建过程中,都有插件进行介入:interceptorChain.pluginAll(...)