先导入mybatis的maven依赖
每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先定制的 Configuration 的实例构建出 SqlSessionFactory 的实例。
从 XML 文件中构建 SqlSessionFactory 的实例非常简单,建议使用类路径下的资源文件进行配置。 但是也可以使用任意的输入流(InputStream)实例,包括字符串形式的文件路径或者 file:// 的 URL 形式的文件路径来配置。MyBatis 包含一个名叫 Resources 的工具类,它包含一些实用方法,可使从 classpath 或其他位置加载资源文件更加容易
XML 配置文件中包含了对 MyBatis 系统的核心设置,包含获取数据库连接实例的数据源(DataSource)和决定事务作用域和控制方式的事务管理器(TransactionManager)
@Test
public void test1() throws IOException {
// 读取mybatis的配置文件
InputStream in = Resources.getResourceAsStream("config/mybatisconfig.xml");
// 创建SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
// 获取session
SqlSession sqlSession = sqlSessionFactory.openSession();
// 动态代理模式获取mapper实例
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
String name = mapper.getUserNameById(1);
System.out.println("test1==============>"+name);
}
首先进入SqlSessionFactoryBuilder.class
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
// 初始化XMLConfigBuilder对象,读取mybatisconfig.xml里面的配置
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
进入parse()方法
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("*[local-name()='configuration']"));
return configuration;
}
进入parseConfiguration(parser.evalNode("*[local-name()=‘configuration’]")),括号里的把标签就是mybatisconfig.xml配置文件里面的标签
private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
propertiesElement(root.evalNode("*[local-name()='properties']"));
Properties settings = settingsAsProperties(root.evalNode("*[local-name()='settings']"));
loadCustomVfs(settings);
loadCustomLogImpl(settings);
typeAliasesElement(root.evalNode("*[local-name()='typeAliases']"));
pluginElement(root.evalNode("*[local-name()='plugins']"));
objectFactoryElement(root.evalNode("*[local-name()='objectFactory']"));
objectWrapperFactoryElement(root.evalNode("*[local-name()='objectWrapperFactory']"));
reflectorFactoryElement(root.evalNode("*[local-name()='reflectorFactory']"));
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
environmentsElement(root.evalNode("*[local-name()='environments']"));
databaseIdProviderElement(root.evalNode("*[local-name()='databaseIdProvider']"));
typeHandlerElement(root.evalNode("*[local-name()='typeHandlers']"));
// 解析节点
mapperElement(root.evalNode("*[local-name()='mappers']"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
上述源码里面的properties,settings等是解析mybatisconfig.xml配置文件里面的标签,如下图:
再进入,propertiesElement(root.evalNode("*[local-name()=‘properties’]"));
private void propertiesElement(XNode context) throws Exception {
if (context != null) {
Properties defaults = context.getChildrenAsProperties();
String resource = context.getStringAttribute("resource");
String url = context.getStringAttribute("url");
if (resource != null && url != null) {
throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference. Please specify one or the other.");
}
if (resource != null) {
// properties加载配置文件
defaults.putAll(Resources.getResourceAsProperties(resource));
} else if (url != null) {
// 根据url加载配置文件
defaults.putAll(Resources.getUrlAsProperties(url));
}
// 讲配置文件中的信息与configuration里面的variables进行合并
Properties vars = configuration.getVariables();
if (vars != null) {
defaults.putAll(vars);
}
// 更新解析器parser和configuration里面的variables
parser.setVariables(defaults);
configuration.setVariables(defaults);
}
}
然后step out这个方法,进入mapperElement(root.evalNode("*[local-name()=‘mappers’]")),XMLMapperBuilder粉墨登场,用于解析mapper.xml
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 {
// 获取resource,url,class三个互斥子节点
String resource = child.getStringAttribute("resource");
String url = child.getStringAttribute("url");
String mapperClass = child.getStringAttribute("class");
// 如果resource子节点不为空
if (resource != null && url == null && mapperClass == null) {
// 加载mapper映射文件
ErrorContext.instance().resource(resource);
InputStream inputStream = Resources.getResourceAsStream(resource);
// 创建XMLMapperBuilder对象,用于解析mapper的映射文件
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
mapperParser.parse();
// 如果url子节点不为空
} else if (resource == null && url != null && mapperClass == null) {
// // 加载mapper映射文件
ErrorContext.instance().resource(url);
InputStream inputStream = Resources.getUrlAsStream(url);
// 创建XMLMapperBuilder对象,用于解析mapper的映射文件
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
mapperParser.parse();
// 如果class子节点不为空
} else if (resource == null && url == null && mapperClass != null) {
// 加载class对象
Class<?> mapperInterface = Resources.classForName(mapperClass);
// 向代理中心注册mapper
configuration.addMapper(mapperInterface);
} else {
throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
}
}
}
}
}
mapperParser.parse();进入mapper解析器
public void parse() {
if (!configuration.isResourceLoaded(resource)) {
configurationElement(parser.evalNode("*[local-name()='mapper']"));
configuration.addLoadedResource(resource);
bindMapperForNamespace();
}
parsePendingResultMaps();
parsePendingCacheRefs();
parsePendingStatements();
}
进入configurationElement(parser.evalNode("*[local-name()=‘mapper’]")),开始解析mapper.xml文件,解析的是mapper.xml的节点而不是每一个sql里面的节点
private void configurationElement(XNode context) {
try {
// 获取命名空间namespace属性
String namespace = context.getStringAttribute("namespace");
if (namespace == null || namespace.equals("")) {
throw new BuilderException("Mapper's namespace cannot be empty");
}
// 设置命名空间namespace属性
builderAssistant.setCurrentNamespace(namespace);
// 解析cache-ref节点
cacheRefElement(context.evalNode("*[local-name()='cache-ref']"));
cacheElement(context.evalNode("*[local-name()='cache']"));
// 解析parameterMap节点
parameterMapElement(context.evalNodes("*[local-name()='parameterMap']"));
// 解析 resultMap节点
resultMapElements(context.evalNodes("*[local-name()='resultMap']"));
sqlElement(context.evalNodes("*[local-name()='sql']"));
// 解析select,update,insert,delete节点
buildStatementFromContext(context.evalNodes("*[local-name()='select' or local-name()='insert' or local-name()='update' or local-name()='delete']"));
} catch (Exception e) {
throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);
}
}
点击进入buildStatementFromContext(context.evalNodes("*[local-name()=‘select’ or local-name()=‘insert’ or local-name()=‘update’ or local-name()=‘delete’]")),重点分析解析select,update,insert,delete节点
// 解析select,update,insert,delete节点
private void buildStatementFromContext(List<XNode> list) {
if (configuration.getDatabaseId() != null) {
buildStatementFromContext(list, configuration.getDatabaseId());
}
buildStatementFromContext(list, null);
}
// 解析所以sql语句节点 ,并注册到configuration中
private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
for (XNode context : list) {
// 创建XMLStatementBuilder对象,专门用于解析sql语句节点
final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
try {
// 解析sql语句节点
statementParser.parseStatementNode();
} catch (IncompleteElementException e) {
configuration.addIncompleteStatement(statementParser);
}
}
}
进入解析sql语句节点方法statementParser.parseStatementNode();
public void parseStatementNode() {
String id = context.getStringAttribute("id");
String databaseId = context.getStringAttribute("databaseId");
if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
return;
}
// 用于解析对应每一个sql节点里面的标签属性
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);
Class<?> resultTypeClass = resolveClass(resultType);
String resultSetType = context.getStringAttribute("resultSetType");
StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
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 Fragments before parsing
XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);
includeParser.applyIncludes(context.getNode());
// Parse selectKey after includes and remove them.
processSelectKeyNodes(id, parameterTypeClass, langDriver);
// Parse the SQL (pre: and were parsed and removed)
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);
if (configuration.hasKeyGenerator(keyStatementId)) {
keyGenerator = configuration.getKeyGenerator(keyStatementId);
} else {
keyGenerator = context.getBooleanAttribute("useGeneratedKeys",
configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))
? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
}
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
resultSetTypeEnum, flushCache, useCache, resultOrdered,
keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}
至此mybatis初始化工作完成,配置文件的所有信息都被加载到了sqlSessionFactory中的configration对象内
如UserMapper mapper = sqlSession.getMapper(UserMapper.class),进入getMapper()
@Override
public <T> T getMapper(Class<T> type) {
/*使用configuration对象得到mapper对象,
而configuration对象以初始化在内存中,
单例模式,生命周期贯穿整个应用周期*/
return configuration.<T>getMapper(type, this);
}
进入getMapper()方法里面
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
// 使用动态代理的方式实现mapper接口,直接到invoke()反射内查看代码
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
// 一个sqlSession对应一个接口方法
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
点击进入mapperProxyFactory.newInstance(sqlSession)
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
MapperProxy创建对象,invoke()反射法动态代理生成mapper对象
public class MapperProxy<T> implements InvocationHandler, Serializable {
private static final long serialVersionUID = -6424540398559729838L;
// 记录关联的sqlSession对象
private final SqlSession sqlSession;
// mapper接口对应的class对象
private final Class<T> mapperInterface;
// key是mapper接口中某个方法的method对象,value对应的是MapperMethod,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;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else if (isDefaultMethod(method)) {
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
// 从缓存中获取一个MapperMethod对象,如果缓存中没有,就创建一个添加到缓存中
final MapperMethod mapperMethod = cachedMapperMethod(method);
//调用excute方法执行sql
return mapperMethod.execute(sqlSession, args);
}
进入执行sql语句的方法mapperMethod.execute(sqlSession, args)
/**
* @author Clinton Begin
* @author Eduardo Macarron
* @author Lasse Voss
*/
public class MapperMethod {
// 从configuration中获取方法的命名空间,方法名以及sql语句的类型
private final SqlCommand command;
// 封装mapper接口方法的相关信息(入参。返回类型)
private final MethodSignature method;
public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
this.command = new SqlCommand(config, mapperInterface, method);
this.method = new MethodSignature(config, mapperInterface, method);
}
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
// 通过sql的类型,接口返回参数,选择对应的INSERT...
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:
// 查看method对象对返回结果类型的判断
if (method.returnsVoid() && method.hasResultHandler()) {
executeWithResultHandler(sqlSession, args);
result = null;
// 返回集合或数组
} else if (method.returnsMany()) {
result = executeForMany(sqlSession, args);
// 返回map
} else if (method.returnsMap()) {
result = executeForMap(sqlSession, args);
// 返回游标
} else if (method.returnsCursor()) {
result = executeForCursor(sqlSession, args);
} else {
// 返回单一对象的情况,通过参数解析器解析
Object param = method.convertArgsToSqlCommandParam(args);
// 查看select返回单个对象的底层实现
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;
}
进入new MethodSignature(config, mapperInterface, method),获取封装mapper的相关参数
public static class MethodSignature {
// 返回相关参数类型的布尔值定义
private final boolean returnsMany;
private final boolean returnsMap;
private final boolean returnsVoid;
private final boolean returnsCursor;
private final Class<?> returnType;
private final String mapKey;
private final Integer resultHandlerIndex;
private final Integer rowBoundsIndex;
// 该方法参数解析器
private final ParamNameResolver paramNameResolver;
public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) {
// 通过解析器解析该方法返回参数的类型
Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
if (resolvedReturnType instanceof Class<?>) {
this.returnType = (Class<?>) resolvedReturnType;
} else if (resolvedReturnType instanceof ParameterizedType) {
this.returnType = (Class<?>) ((ParameterizedType) resolvedReturnType).getRawType();
} else {
this.returnType = method.getReturnType();
}
// 初始化返回值字段
this.returnsVoid = void.class.equals(this.returnType);
this.returnsMany = (configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray());
this.returnsCursor = Cursor.class.equals(this.returnType);
this.mapKey = getMapKey(method);
this.returnsMap = (this.mapKey != null);
this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
this.paramNameResolver = new ParamNameResolver(configuration, method);
}
再进入selectOne()方法查看底层实现
@Override
public <T> T selectOne(String statement, Object parameter) {
// Popular vote was to return null on 0 results and throw exception on too many.
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 <K, V> Map<K, V> selectMap(String statement, String mapKey) {
return this.selectMap(statement, null, mapKey, RowBounds.DEFAULT);
}
@Override
public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {
return this.selectMap(statement, parameter, mapKey, RowBounds.DEFAULT);
}
@Override
public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
final List<? extends V> list = selectList(statement, parameter, rowBounds);
final DefaultMapResultHandler<K, V> mapResultHandler = new DefaultMapResultHandler<K, V>(mapKey,
configuration.getObjectFactory(), configuration.getObjectWrapperFactory(), configuration.getReflectorFactory());
final DefaultResultContext<V> context = new DefaultResultContext<V>();
for (V o : list) {
context.nextResultObject(o);
mapResultHandler.handleResult(context);
}
return mapResultHandler.getMappedResults();
}
由此可知不管是返回的单个对象,还是map,或是其他的,底层都是通过selectList()方法,返回list集合,最后做的转换
sqlSession查询接口嵌套关系:
Executor的三个重要组件
接着上一段源码,进入selelectList()方法
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
// 从configuration中获取要执行sql语句执行信息
MappedStatement ms = configuration.getMappedStatement(statement);
// 此处进入数据库阶段,通过executor执行sql语句,并返回指定结果集
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();
}
}
再进入query()方法
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
// 获取sql语句信息,包括占位符,参数等信息
BoundSql boundSql = ms.getBoundSql(parameter);
// 拼装缓存的key值
CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
@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());
// 检查exector是否关闭
if (closed) {
throw new ExecutorException("Executor was closed.");
}
// 非嵌套查询并且FlushCache配置为true,则要清空一级缓存
if (queryStack == 0 && ms.isFlushCacheRequired()) {
clearLocalCache();
}
List<E> list;
try {
// 查询层次加1
queryStack++;
// 查询以及缓存
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
// 针对存储过程的结果处理
if (list != null) {
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();
}
// issue #601
deferredLoads.clear();
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
// issue #482
clearLocalCache();
}
}
return list;
}
进入真正访问数据库的方法queryFromDatabase()
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 {
// 调用doQuery()方法并接收返回结果
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;
}
进入查询的实现方法doQuery(),模板设计模式由子类实现3个方法,批量数据库操作,缓存预编译处理,默认处理器 (依次对应)
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
// 获取configuration对象
Configuration configuration = ms.getConfiguration();
// StatementHandler创建对象handler
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
// 使用prepareStatement()预编译对占位符进行处理
stmt = prepareStatement(handler, ms.getStatementLog());
// 通过StatmentHandler调用ResultSetHandler将结果集转化为指定对象返回
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
进入prepareStatement()预编译处理
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
// 创建Statement
Statement stmt;
// 通过动态代理获取connect对象,并添加日志功能
Connection connection = getConnection(statementLog);
// 通过不同的StatementHandler,利用connect创建Statement
stmt = handler.prepare(connection, transaction.getTimeout());
// 使用parameterize()处理占位符
handler.parameterize(stmt);
return stmt;
}
parameterHandlder主键以及饥渴难耐,进入parameterize()处理占位符
@Override
public void parameterize(Statement statement) throws SQLException {
// parameterHandler主键开始进行占位符处理
parameterHandler.setParameters((PreparedStatement) statement);
}
进入setParameters(),进入占位符处理的具体业务
@Override
public void setParameters(PreparedStatement ps) {
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
// 从boundSql中获取sql语句占位符参数信息
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);
}
// 从parameterMapping中获取typeHandler
TypeHandler typeHandler = parameterMapping.getTypeHandler();
// 获取对应参数的jdbcType
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) {
jdbcType = configuration.getJdbcTypeForNull();
}
try {
typeHandler.setParameter(ps, i + 1, value, jdbcType);
} catch (TypeException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
} catch (SQLException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
}
}
}
}
}
占位符处理完毕开始执行sql,进入handler.query(stmt, resultHandler)
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
// 似曾相识的jdbc操作
PreparedStatement ps = (PreparedStatement) statement;
// 执行sql语句
ps.execute();
// resultSetHandler对sql结果进行处理
return resultSetHandler.<E> handleResultSets(ps);
}
进入resultSetHandler. handleResultSets(ps),查看sql返回结果处理
@Override
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;
// statement肯返回多个结果集的对象,这里先取第一个
ResultSetWrapper rsw = getFirstResultSet(stmt);
// 获取结果集resultMap,本质就是获取字段与java属性的映射
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
validateResultMapsCount(rsw, resultMapCount);
// 获取结果集不能为空,为空抛出异常
while (rsw != null && resultMapCount > resultSetCount) {
// 获取当前结果集对应的resultMap
ResultMap resultMap = resultMaps.get(resultSetCount);
// 根据映射规则(resultMap)对结果集进行转化,并放入multipleResults
handleResultSet(rsw, resultMap, multipleResults, null);
// 获取下一个结果集
rsw = getNextResultSet(stmt);
// 清空nestedResuletsetObject对象
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
//获取多结果集,多结果集多存在与存储过程,返回多个resultSets,下次更新
String[] resultSets = mappedStatement.getResultSets();
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++;
}
}
Excutor内幕结构流程:
Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Opening JDBC Connection
Created connection 2104545713.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@7d70d1b1]
==> Preparing: select name from t_user where id=?
==> Parameters: 1(Integer)
<== Columns: name
<== Row: 张三
<== Total: 1
test1==============>张三