- 在研究select执行过程之前先来介绍一个重要的类
一、SqlNode和SqlSource
- 在myabtis初始化过程中可以知道,映射配置文件中的sql节点会被解析为MappedStatement对象,其中sql语句解析成SqlSource对象,sql语句中定义的Sql节点、文本节点等,则由SqlNode接口的响应实现。
1、SqlSource接口
public interface SqlSource {
//通过解析得到BoundSql对象,其中封装了包含?占位符号的sql语句以及绑定的实参
BoundSql getBoundSql(Object parameterObject);
}
2、SqlNode
public interface SqlNode {
//根据用户传入的实际参数,解析该sqlNode所记录的动态的sql节点,当sql节点下的所有sqlnode
//完成解析后,我们就可以从dynamicContext中获取一条动态生成的完整的sql语句。
boolean apply(DynamicContext context);
}
- sqlNode有很多的实现类,比如ChooseSqlNode、ForEachSqlNode等
二、StatementHandler
-
核心接口,完成mybatis中最核心的工作,接口功能很多,例如创建statement对象,为sql语句绑定实际参数,执行select、insert等多种类型的sql语句,并将结果集映射成结果对象。
1、RoutingStatementHandler
- 很根据MapperdStatement中指定的statementType字段,创建相应的StatementHandler接口实现。
2、BaseStatementHandler
- 实现了Statementhandler接口的抽象类,只提供了参数绑定的相关方法,并没有具体操作数据库的方法。依赖于ParameterHandler和ResultSetHandler组件
- 实现了 StatementHandler接口中的prepare方法,该方法中调用instantiateStatement抽象方法初始化statement对象,然后配置相关的参数
3、PreparedStatementHandler等
- 是BaseStatementHandler的实现类,是具体操作sql的地方
三、ResultHandler
- StatementHandler接口在执行完指定的select语句之后,会将查询得到的结果集交给ResultSetHandler完成映射处理,ResultSetHandler除了负责映射select语句得到的结果集还会处理存储过程执行后的输出参数
public interface ResultSetHandler {
//处理结果集生成相应的结果对象集合
List handleResultSets(Statement stmt) throws SQLException;
//处理结果集,返回相应的游标对象
Cursor handleCursorResultSets(Statement stmt) throws SQLException;
//处理存储过程的输出对象
void handleOutputParameters(CallableStatement cs) throws SQLException;
}
1、DefaultResultSetHandler实现类
- 重要的属性:
private final Executor executor;
private final Configuration configuration;
private final MappedStatement mappedStatement;
private final RowBounds rowBounds;
private final ParameterHandler parameterHandler;
//用户指定用于处理结果的ResultHandler对象
private final ResultHandler> resultHandler;
private final BoundSql boundSql;
private final TypeHandlerRegistry typeHandlerRegistry;
private final ObjectFactory objectFactory;
private final ReflectorFactory reflectorFactory;
四、select的执行流程
1、方法入口,执行代理接口的invoke方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//判断方法的父类是否是Object如果是就直接调用
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
}
//获取MapperMethod并缓存
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
private final Map methodCache;
1、获取MapperMethod时候先判断methodCache有没有,没有的话那么直接创建然后放入methodCache中(下次调用直接从map中获取)
private MapperMethod cachedMapperMethod(Method method) {
MapperMethod mapperMethod = methodCache.get(method);
if (mapperMethod == null) {
//构建mapperMethod方法
mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
methodCache.put(method, mapperMethod);
}
return mapperMethod;
}
2、创建MapperMethod对象,SqlCommand和MethodSignature是MapperMethod的内部类
public MapperMethod(Class> mapperInterface, Method method, Configuration config) {
//SqlCommand包含了mapper.xml文件中的相关sql语句及属性信息
this.command = new SqlCommand(config, mapperInterface, method);
//MethodSignature包含了mapper接口方法签名的信息
this.method = new MethodSignature(config, method);
}
2.1、获取SqlCommand
public SqlCommand(Configuration configuration, Class> declaringInterface, Method method) throws BindingException {
//包名+方法名作为唯一的id
name = declaringInterface.getName() + "." + method.getName();
final MappedStatement ms;
try {
//根据id获取
ms = configuration.getMappedStatement(name);
} catch (Exception e) {
throw new BindingException("Invalid bound statement (not found): " + name, e);
}
//获取crud类型如果是unknown就报错误
type = ms.getSqlCommandType();
if (type == SqlCommandType.UNKNOWN) {
throw new BindingException("Unknown execution method for: " + name);
}
}
2.2、获取MethodSignature
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);
}
2、执行MapperMethod的execute方法
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
//根据SqlCommand类型判断是执行curd的哪一个
//insert
if (SqlCommandType.INSERT == command.getType()) {
//将参数转换为sql命令的参数
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
//update
} else if (SqlCommandType.UPDATE == command.getType()) {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
//delete
} else if (SqlCommandType.DELETE == command.getType()) {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
//select
} else if (SqlCommandType.SELECT == command.getType()) {
//MethodSignature方法签名的返回类型来进行不同的逻辑处理
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 {
//当不满足上面需求的时候进行这一步操作,先进行参数解析,包装为map返回
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;
}
3、DefaultSqlSession中执行sqlSession.selectOne方法
public T selectOne(String statement, Object parameter) {
// 调用selectList获取list列表,然后获取第一个。如果有多个那么就直接报错误
List list = this.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;
}
}
4、归根结底还是调用executor的query方法来执行
public List selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
////根据statementId获取MappedStatement,MappedStatement封装了增删改查的详细信息
MappedStatement ms = configuration.getMappedStatement(statement);
//调用executor的query
List 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();
}
}
//包装参数为map类型
private Object wrapCollection(final Object object) {
if (object instanceof List) {
StrictMap
5、执行cachingExecutor的query方法,
public List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
//获取解析过动态标签的sql,BoundSql包含当前sql语句的详细信息和参数
BoundSql boundSql = ms.getBoundSql(parameterObject);
//创建缓存key
CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
6、获取BoundSql
public BoundSql getBoundSql(Object parameterObject) {
/*获取解析过动态标签的sql*/
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
List parameterMappings = boundSql.getParameterMappings();
if (parameterMappings == null || parameterMappings.size() <= 0) {
boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);
}
// 检查参数映射中是否存在嵌套的resultMap并设置boolean标记
for (ParameterMapping pm : boundSql.getParameterMappings()) {
String rmId = pm.getResultMapId();
if (rmId != null) {
ResultMap rm = configuration.getResultMap(rmId);
if (rm != null) {
hasNestedResultMaps |= rm.hasNestedResultMaps();
}
}
}
return boundSql;
}
7、执行BaseExecutor的query
public List 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, key, parameterObject, boundSql);
if (!dirty) {
cache.getReadWriteLock().readLock().lock();
try {
@SuppressWarnings("unchecked")
List cachedList = (List) cache.getObject(key);
if (cachedList != null) return cachedList;
} finally {
cache.getReadWriteLock().readLock().unlock();
}
}
List list = delegate. 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.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
public List 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 list;
try {
queryStack++;
list = resultHandler == null ? (List) 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();
}
deferredLoads.clear(); // issue #601
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
clearLocalCache(); // issue #482
}
}
return list;
}
private List queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
List 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;
}
8、这里在SimpleExecutor中真正的执行query(根据配置还可以在选择其他的Executor)
public List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
//创建statementhandler,statementhandler是创建原生statement的处理器
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, rowBounds, resultHandler, boundSql);
//准备Statement
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
9、构建StatementHandler
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
/*构造RoutingStatementHandler*/
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
//拦截器执行
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
//终于柳暗花明了
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
//根据MappedStatement中的statement类型来创建响应的statement处理器
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());
}
}
10、statement的准备
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
//获取数据库连接
Connection connection = getConnection(statementLog);
//进行响应的statement的转呗工作
stmt = handler.prepare(connection);
//给statement设置参数
handler.parameterize(stmt);
return stmt;
}
public Statement prepare(Connection connection) throws SQLException {
ErrorContext.instance().sql(boundSql.getSql());
Statement statement = null;
try {
//实例化对象的statement
statement = instantiateStatement(connection);
//设置超时时间
setStatementTimeout(statement);
//设置FetchSize
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为例:
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);
}
}
11、设置参数过程
public void setParameters(PreparedStatement ps) {
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
List 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)) {
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 jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) {
jdbcType = configuration.getJdbcTypeForNull();
}
try {
/*为PreparedStatement设置值*/
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);
}
}
}
}
}
12、最后执行查询并进行参数封装
public List query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
//执行sql语句
ps.execute();
//参数封装
return resultSetHandler. handleResultSets(ps);
}