第一节 参考
一.参考资料
https://github.com/mybatis/mybatis-3
mybatis的单元测试用的hsqldb数据库,需要自己建个单元测试用例, 连接mysql.我的测试用例如下图所示.
第二节 架构
一.分层
核心原理三步走:
1.启动读取xml配置,解析到Configuration类中,以Configuration为构造方法参数创建SqlSessionFactory
2.通过DefaultSqlSessionFactory类创建DefaultSqlSession,通过DefaultSqlSession获取到mapper接口的代理类.
3.通过mapper接口的代理类执行sql语句
具体过程:
Configuration+代理+命令模式+委托模式。
所有的mybatis配置读取xml到Configuration类中. 然后调用MapperProxyFactory类,生成所有mapper接口类的代理类MapperProxy.在MapperProxy类的invoke方法中,调用MapperMethod.execute方法中执行各种命令.具体命令由RoutingStatementHandler委托具体的类处理,执行由STATEMENT,PREPARED,CALLABLE类型的具体类型处理.
二.SqlSessionFactoryBuilder/SqlSessionFactory
三.SqlSession
四.Configuration
五.Executor
六.BoundSql
七.StatementHandler
八.ResultSetHandler
第三节 源码细节
一.启动读取xml配置,创建SqlSessionFactory
调用SqlSessionFactoryBuilder#build(Reader)使用builder模式创建创建SqlSessionFactory.入参是是xml文件生成的Reader.主要是填充Configuration类对象,然后把这个对象作为DefaultSqlSessionFactory构造方法的参数.
xml文件使用sax库解析到XMLConfigBuilder类中.然后进入XMLConfigBuilder#parseConfiguration(XNode)解析到Configuration类型的BaseBuilder#configuration成员中.XMLConfigBuilder类继承自BaseBuilder类,BaseBuilder类中成员如下:
public abstract class BaseBuilder {
//xml中的各种配置
protected final Configuration configuration;
protected final TypeAliasRegistry typeAliasRegistry;
protected final TypeHandlerRegistry typeHandlerRegistry;
}
1.解析xml内容的方法XMLConfigBuilder#parseConfiguration()代码如下:
private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
/* 解析properties标签中的name value值存储到Properties类型的Configuration#variables成员中
比如示例代码中的<property name="dialect" value="mysql" /> */
propertiesElement(root.evalNode("properties"));
/* 解析setting标签为Properties格式,比如示例中的<setting name="mapUnderscoreToCamelCase" value="true" /> */
Properties settings = settingsAsProperties(root.evalNode("settings"));
//解析VFS的子类放到Configuration#vfsImpl成员中,没用过
loadCustomVfs(settings);
//解析Log接口的实现类放到Configuration#logImpl成员中,没用过
loadCustomLogImpl(settings);
/* 解析typeAliases,调用TypeAliasRegistry#registerAliases()注册类型别名到TypeAliasRegistry#TYPE_ALIASES成员Map中*/
typeAliasesElement(root.evalNode("typeAliases"));
/*注册plugins插件到类型为InterceptorChain的Configuration#interceptorChain中*/
pluginElement(root.evalNode("plugins"));
/*解析objectFactory到类型为ObjectFactory的Configuration#objectFactory成员中*/
objectFactoryElement(root.evalNode("objectFactory"));
/*解析objectWrapperFactory到类型为ObjectWrapperFactory的成员Configuration#objectWrapperFactory中*/
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
/*解析reflectorFactory标签到类型为ReflectorFactory的成员Configuration#reflectorFactory中*/
reflectorFactoryElement(root.evalNode("reflectorFactory"));
/*解析setting标签到configuration成员中,具体支持的设置项入下面代码2处所示.*/
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
/*解析environments标签到类型为Environment的成员Configuration#environment中这里面存放了jdbc连接的配置,Environment类成员在下面代码给出*/
environmentsElement(root.evalNode("environments"));
/*解析databaseIdProvider标签的值到Configuration#databaseId*/
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
/*解析typeHandlers到TypeHandlerRegistry#TYPE_HANDLER_MAP的成员map中*/
typeHandlerElement(root.evalNode("typeHandlers"));
/*注册所有xml的mapper文件,内部逻辑是针对每个xml文件,创建XMLMapperBuilder对象,调用XMLMapperBuilder#parse()解析mapper文件,代码在后面3处分析*/
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
Environment类成员:
public final class Environment {
private final String id;
private final TransactionFactory transactionFactory;
private final DataSource dataSource;
}
2.mybatis支持的setting配置项
进入XMLConfigBuilder#settingsElement()方法,代码如下:
private void settingsElement(Properties props) {
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"), false));
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.setDefaultEnumTypeHandler(resolveClass(props.getProperty("defaultEnumTypeHandler")));
configuration.setCallSettersOnNulls(booleanValueOf(props.getProperty("callSettersOnNulls"), false));
configuration.setUseActualParamName(booleanValueOf(props.getProperty("useActualParamName"), true));
configuration.setReturnInstanceForEmptyRow(booleanValueOf(props.getProperty("returnInstanceForEmptyRow"), false));
configuration.setLogPrefix(props.getProperty("logPrefix"));
configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory")));
}
3.解析mapper的xml文件
进入XMLMapperBuilder#parse(),代码如下:
public void parse() {
if (!configuration.isResourceLoaded(resource)) {
/*代码在下面分析*/
configurationElement(parser.evalNode("/mapper"));
//把当前的mapper文件加到Configuration#loadedResources的set中,代表已经加载过
configuration.addLoadedResource(resource);
/* 把当前解析的mapper对应的class加到MapperRegistry#knownMappers的成员中,key是Class对象,value是MapperProxyFactory类型,这个MapperProxyFactory是直接new出来的泛型类对象,泛型指向mapper文件对应的Class接口类型,比如xxx.UserMapper.然后调用MapperAnnotationBuilder#parse()方法解析Mapper文件对应的Class接口中的每个方法上面的注解。这种在接口方法上面通过注解写sql语句的方法比较少用,不方便.*/
bindMapperForNamespace();
}
//解析之前不完整的ResultMap标签,示例代码没有
parsePendingResultMaps();
//解析之前不完整的cacheref标签,示例代码没有
parsePendingCacheRefs();
//解析之前不完整的statement语句,示例代码没有
parsePendingStatements();
}
解析mapper文件标签
private void configurationElement(XNode context) {
try {
//获取namespace,比如com.xx.UserMapper接口,成员方法对应xml的每个sql语句
String namespace = context.getStringAttribute("namespace");
if (namespace == null || namespace.equals("")) {
throw new BuilderException("Mapper's namespace cannot be empty");
}
builderAssistant.setCurrentNamespace(namespace);
//解析cache-ref标签到Configuration#cacheRefMap中
cacheRefElement(context.evalNode("cache-ref"));
//解析cache缓存标签到Configuration#caches成员中.
cacheElement(context.evalNode("cache"));
//解析parameterMap标签到Configuration#parameterMaps成员中.
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
/*resultMap代表damain对象中字段,类型和数据库列的一一映射关系.解析到Configuration#resultMaps成员map中,key是id,value是个ResultMap类.这个类的成员在下面4给出.*/
resultMapElements(context.evalNodes("/mapper/resultMap"));
/*遍历所有的sql片段语句到XMLMapperBuilder#sqlFragments的map中.key是sql的id.value是XNode格式.*/
sqlElement(context.evalNodes("/mapper/sql"));
/*遍历所有的sql语句,解析到Configuration#mappedStatements的map中,key是id,value是MappedStatement类,代表一个sql语句,它的类成员在后面4给出.*/
buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
} catch (Exception e) {
throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);
}
}
4.存储xml标签和sql语句的一些数据类.
ResultMap类,代表domain对象和数据库表的列的映射关系,代码如下:
public class ResultMap {
private Configuration configuration;
private String id;
private Class<?> type;
private List<ResultMapping> resultMappings;
private List<ResultMapping> idResultMappings;
private List<ResultMapping> constructorResultMappings;
private List<ResultMapping> propertyResultMappings;
private Set<String> mappedColumns;
private Set<String> mappedProperties;
private Discriminator discriminator;
private boolean hasNestedResultMaps;
private boolean hasNestedQueries;
private Boolean autoMapping;
}
代表一个mapper中select|insert|update|delete的sql语句的类.代码如下:
public final class MappedStatement {
//xml文件的全路径
private String resource;
private Configuration configuration;
//sql语句的全路径,比如com.xxx.UserMapper.selectByExample
private String id;
private Integer fetchSize;
private Integer timeout;
/*语句类型,枚举值enum StatementType {
STATEMENT, PREPARED, CALLABLE
}, 默认是PREPARED枚举*/
private StatementType statementType;
//默认是Default枚举
private ResultSetType resultSetType;
//原始的sql语句,默认是DynamicSqlSource类型,内有SqlNode类型的rootSqlNode成员存储sql语句.在后面给出SqlNode类成员.
private SqlSource sqlSource;
private Cache cache;
private ParameterMap parameterMap;
private List<ResultMap> resultMaps;
private boolean flushCacheRequired;
private boolean useCache;
private boolean resultOrdered;
/*sql命令类型,枚举值 enum SqlCommandType {
UNKNOWN, INSERT, UPDATE, DELETE, SELECT, FLUSH;
}
*/
private SqlCommandType sqlCommandType;
private KeyGenerator keyGenerator;
private String[] keyProperties;
private String[] keyColumns;
private boolean hasNestedResultMaps;
private String databaseId;
private Log statementLog;
private LanguageDriver lang;
private String[] resultSets;
}
存储Sql语句的递归结构
public class MixedSqlNode implements SqlNode {
private final List<SqlNode> contents;
}
二.通过DefaultSqlSessionFactory类获取到mapper接口的代理类.
1.DefaultSqlSessionFactory#openSession()获取SqlSession对象.进入DefaultSqlSessionFactory#openSessionFromDataSource()方法创建SqlSession.代码如下:
参数ExecutorType是枚举类型,默认是SIMPLE.
public enum ExecutorType {
SIMPLE, REUSE, BATCH
}
参数TransactionIsolationLevel隔离级别也是枚举.
public enum TransactionIsolationLevel {
NONE(Connection.TRANSACTION_NONE),
READ_COMMITTED(Connection.TRANSACTION_READ_COMMITTED),
READ_UNCOMMITTED(Connection.TRANSACTION_READ_UNCOMMITTED),
REPEATABLE_READ(Connection.TRANSACTION_REPEATABLE_READ),
SERIALIZABLE(Connection.TRANSACTION_SERIALIZABLE);
}
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
//获取xml文件中配置的jdbc连接参数.
final Environment environment = configuration.getEnvironment();
//获取事务工厂为JdbcTransactionFactory类
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
//创建一个Transaction事务对象,jdbc的为JdbcTransaction.类成员在后面2给出
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//默认创建SimpleExecutor执行器.作为CachingExecutor缓存执行器的成员,委托模式.
//如果有Interceptor,在这里InterceptorChain#interceptors成员添加拦截这个CachingExecutor执行器.
final Executor executor = configuration.newExecutor(tx, execType);
//创建DefaultSqlSession对象返回,DefaultSqlSession成员在后面2给出
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();
}
}
2.Jdbc事务对象
public class JdbcTransaction implements Transaction {
//事务所在连接
protected Connection connection;
//数据源,连接的数据库地址,密码等
protected DataSource dataSource;
//事务隔离级别
protected TransactionIsolationLevel level;
//默认为false,不自动提交
protected boolean autoCommit;
}
默认的Sql会话类
public class DefaultSqlSession implements SqlSession {
private final Configuration configuration;
//执行器,默认CachingExecutor中引用SimpleExecutor.
private final Executor executor;
//默认为false
private final boolean autoCommit;
private boolean dirty;
private List<Cursor<?>> cursorList;
}
3.通过DefaultSqlSession获取mapper接口的代理类
进入DefaultSqlSession#getMapper(),参数为xxx.UserMapper的接口Class.实际调用成员Configuration#mapperRegistry的getMapper方法,mapperRegistry的填充在前面一.3中分析了.MapperRegistry#knownMappers的key是Class对象,value是MapperProxyFactory类型,这个MapperProxyFactory是直接new出来的泛型类对象,泛型指向mapper文件对应的Class接口类型,比如xxx.UserMapper代码如下:
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
//获取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 {
//创建mapper接口的代理对象,代码如下所示
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
public T newInstance(SqlSession sqlSession) {
//MapperProxy实现了InvocationHandler接口,是代理类,所有这个mapper的sql语句都调用它的invoke方法
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
//代码在下面,调用Proxy.newProxyInstance创建代理类,代理类调用MapperProxy类.
return newInstance(mapperProxy);
}
创建动态代理
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
mapper接口代理类
public class MapperProxy<T> implements InvocationHandler, Serializable {
private final SqlSession sqlSession;
//代理的mapper接口
private final Class<T> mapperInterface;
private final Map<Method, MapperMethod> methodCache;
//sql语句代理方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
//代理类的常规想法,去掉Object的方法
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else if (isDefaultMethod(method)) {
//如果是静态,abstract方法,调用原对象
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
/*取出缓存MapperProxy#methodCache中的MapperMethod对象,开始是空的.创建MapperMethod对象后放进去,MapperMethod类成员下面给出*/
final MapperMethod mapperMethod = cachedMapperMethod(method);
//执行sql语句
return mapperMethod.execute(sqlSession, args);
}
}
public class MapperMethod {
//方法对应的sql命令,包含方法名全路径,方法类型
private final SqlCommand command;
//方法签名,在下面给出类成员
private final MethodSignature method;
}
方法签名类
public static class MethodSignature {
//是否返回多条记录
private final boolean returnsMany;
private final boolean returnsMap;
private final boolean returnsVoid;
private final boolean returnsCursor;
private final boolean returnsOptional;
//返回类型
private final Class<?> returnType;
private final String mapKey;
private final Integer resultHandlerIndex;
private final Integer rowBoundsIndex;
private final ParamNameResolver paramNameResolver;
}
三.通过mapper接口的代理类执行sql语句.
1.比如执行Employee employee = employeeMapper.selectByPrimaryKey(id)语句.
通过上面二.3的最后分析,进入MapperProxy#invoke()方法,调用MapperMethod#execute().通过命令模式实现,代码如下:
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:
//根据select的返回多条记录,一条记录,还是map等调用不同方法.
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 {
//上面的selectByPrimaryKey(id)测试代码进入这里.
//把传进来的sql语句的参数转成Map<String, Object>类型的param
Object param = method.convertArgsToSqlCommandParam(args);
//执行sql查询,测试代码进入DefaultSqlSession#selectOne()方法,代码在后面2处分析,策略模式
result = sqlSession.selectOne(command.getName(), param);
if (method.returnsOptional() &&
(result == null || !method.getReturnType().equals(result.getClass()))) {
result = Optional.ofNullable(result);
}
}
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;
}
2.select类型的sql查询
如果只返回一条记录,进入DefaultSqlSession#selectOne().调用DefaultSqlSession#selectList(),代码如下:
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
/* 取出xml填充到Configuration#mappedStatements中的sql语句.这个填充过程在前面一.3处分析过了.MappedStatement类成员代码在前面的一.4中有。具体的sql语句在MappedStatement#sqlSource成员中递归存储*/
MappedStatement ms = configuration.getMappedStatement(statement);
//调用CachingExecutor#query(),代码在下面分析
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();
}
}
缓存执行器执行查询CachingExecutor#query(),代码如下:
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
//创建动态sql
BoundSql boundSql = ms.getBoundSql(parameterObject);
//缓存sql语句,key为为xml中的sql语句id+offset+limit+sql语句
CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
//调用代码在下面
return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
动态sql类BoundSql成员,里面有?,#{id}等占位符
public class BoundSql {
//存放字符串形式的具体的sql语句
private final String sql;
private final List<ParameterMapping> parameterMappings;
private final Object parameterObject;
private final Map<String, Object> additionalParameters;
private final MetaObject metaParameters;
}
缓存执行器执行查询CachingExecutor#query(),代码如下:
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, boundSql);
@SuppressWarnings("unchecked")
List<E> list = (List<E>) tcm.getObject(cache, key);
if (list == null) {
list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
/* 没有缓存,调用BaseExecutor#query()方法执行,进入BaseExecutor#queryFromDatabase(),代码在下面分析*/
return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
BaseExecutor#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 {
//调用SimpleExecutor#doQuery()执行查询.在后面的3处分析
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;
}
3. SimpleExecutor#doQuery()执行查询.代码如下:
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();
/* 创建RoutingStatementHandler执行sql.加入StatementHandler的目的是用来区分StatementType枚举的三种调用STATEMENT, PREPARED, CALLABLE.如下面的RoutingStatementHandler类的构造方法所示,每种枚举对应不同的StatementHandler*/
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
//调用SimpleExecutor#prepareStatement()准备sql语句,准备过程在下面分析
stmt = prepareStatement(handler, ms.getStatementLog());
//调用jdbc执行sql查询,代码在后面分析
return handler.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
RoutingStatementHandler创建不同的种类的StatementHandler.内部成员delegate委托模式具体执行sql语句.
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:
//默认是预编译类型的语句处理器
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());
}
}
准备sql语句,进入SimpleExecutor#prepareStatement()
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
//调用JdbcTransaction#openConnection(),进入javax.sql.DataSource#getConnection()获取数据库连接
Connection connection = getConnection(statementLog);
//处理sql语句的占位符
stmt = handler.prepare(connection, transaction.getTimeout());
handler.parameterize(stmt);
return stmt;
}
调用jdbc执行sql查询,向mysql通过socket发出sql语句.进入SimpleStatementHandler#query,如下代码所示:
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
String sql = boundSql.getSql();
//调用jdbc的方法java.sql.Statement#execute(java.lang.String)执行sql语句
statement.execute(sql);
return resultSetHandler.handleResultSets(statement);
}