2. SQL 执行流程
SELECT
graph LR
mapper-interface --> MapperProxy.invoke --> 根据类型调用sqlSession的查询方法
根据类型调用sqlSession的查询方法--> 返回的结果类型为空并且存在结果处理器 --> 调用SqlSessionTemplate.select方法 --> 调用默认实现的DefaultSqlSession的select方法 --> 调用executor.query --> 调用StatementHandler.query方法
根据类型调用sqlSession的查询方法--> 返回的结果类型为集合 --> 调用SqlSessionTemplate.selectList方法 --> 调用默认实现的DefaultSqlSession的selectList方法 --> 调用executor.query --> 调用StatementHandler.query方法
根据类型调用sqlSession的查询方法--> 返回的结果类型为MAP --> 调用SqlSessionTemplate.selectMap方法 --> 调用默认实现的DefaultSqlSession的selectMap方法 --> 调用executor.query --> 调用StatementHandler.query方法
根据类型调用sqlSession的查询方法--> 返回的结果类型为坐标 --> 调用SqlSessionTemplate.selectCursor方法 --> 调用默认实现的DefaultSqlSession的selectCursor方法 --> 调用executor.queryCursor --> 调用StatementHandler.query方法
根据类型调用sqlSession的查询方法--> 返回的结果类型为非以上场景 --> 调用SqlSessionTemplate.selectOne方法 --> 调用默认实现的DefaultSqlSession的selectOne方法 --> 调用executor.query --> 调用StatementHandler.query方法
调用StatementHandler.query方法 --> 添加本地缓存 --> 根据返回类型处理结果
- 判断查询的结果
-
如果查询结果返回为void 并且有结果处理器,那么 处理完 直接返回null (使用:正常配置resultMap,在参数中设置ResultHandler)
- 处理参数
- 判断是否分页,如果分页执行 sqlSession.select(x,x,rowBounds,ResultHandler)方法
- 如果不分页执行 sqlSession.select(x,x,ResultHandler)方法
- 调用CachingExecutor的query方法 (如果缓存中有直接获取缓存对象,如果缓存中没有调用BaseExecutor的query方法(见2.1 Executor)
- 根据Configuration的ExecutorType执行器类型最终调用子方法的doQuery方法
- 再根据Configuration这个方法的MappedStatement构建Statement,Statement.query方法(见2.2 StatementHandler),构建结果的时候检查结果是否有结果处理器,如果有就执行
- return null;
-
如果查询结果的是集合 那么执行 executeForMany 方法 (使用:返回值为List或者Collection的实现类)
- 处理参数
- 判断是否分页,如果分页执行 sqlSession.selectList(x,x,rowBounds)方法
- 如果不分页执行 sqlSession.selectList(x,x)方法
- 调用CachingExecutor的query方法 (如果缓存中有直接获取缓存对象,如果缓存中没有调用BaseExecutor的query方法(见2.1 Executor)
- 根据Configuration的ExecutorType执行器类型最终调用子方法的doQuery方法
- 再根据Configuration这个方法的MappedStatement构建Statement,Statement.query方法(见2.2 StatementHandler)
- 判断类型是否匹配,如果类型不匹配判断是不是数组,如果是数组进行转换为数组,如果不是 数组转换为结果
-
如果查询结果的Map 那么执行 executeForMap 方法 (使用:resultType="java.util.HashMap",方法添加@MapKey注解)
- 处理参数
- 判断是否分页,如果分页执行 sqlSession.selectMap(x,x,mapKey,rowBounds)方法
- 如果不分页执行 sqlSession.selectMap(x,x,mapKey)方法
- 调用CachingExecutor的query方法 (如果缓存中有直接获取缓存对象,如果缓存中没有调用BaseExecutor的query方法(见2.1 Executor)
- 根据Configuration的ExecutorType执行器类型最终调用子方法的doQuery方法,
- 再根据Configuration这个方法的MappedStatement构建Statement,Statement.query方法(见2.2 StatementHandler)
- 创建一个MAP结果执行器
- 循环结果 将最终结果根据mapKey转换为MAP
-
如果查询结果的Cursor 那么执行 executeForCursor 方法
- 处理参数
- 执行 sqlSession.selectOne(x,x)方法
-
调用sqlSession.selectList(x,x)方法
- 调用CachingExecutor的query方法 (如果缓存中有直接获取缓存对象,如果缓存中没有调用BaseExecutor的query方法(见2.1 Executor)
- 根据Configuration的ExecutorType执行器类型最终调用子方法的doQuery方法,
- 再根据Configuration这个方法的MappedStatement构建Statement,Statement.queryCursor方法(见2.2 StatementHandler)
-
获取的结果判断结果大小,如果超过1个抛出异常
-
获取List的第一个结果
-
Cursor 获取对象最终调用handleRowValues方法(实例化通过constructor.newInstance(),属性通过包装类的方法缓存(MAP)将值通过反射调用SET方法写入对象中)
-
否则 处理参数 后 执行 selectOne方法
- 处理参数
- 判断是否分页,如果分页执行 sqlSession.selectCursor(x,x,rowBounds)方法
- 如果不分页执行 sqlSession.selectCursor(x,x)方法
- 调用CachingExecutor的query方法 (如果缓存中有直接获取缓存对象,如果缓存中没有调用BaseExecutor的query方法(见2.2 Executor)
- 根据Configuration的ExecutorType执行器类型最终调用子方法的doQuery方法,
- 再根据Configuration这个方法的MappedStatement构建Statement,Statement.queryCursor方法(见2.3 StatementHandler)
- 返回Cursor 对象
-
UPDATE
graph LR
mapper-interface --> MapperProxy.invoke --> 根据类型调用sqlSession的修改方法 --> 返回的结果类型为空并且存在结果处理器 --> 调用SqlSessionTemplate.update方法 --> 调用默认实现的DefaultSqlSession的update方法 --> 调用executor.update --> 调用StatementHandler.update方法
- 将参数转换为Sql命令参数
- 调用sqlSession.update(command.getName(), param)方法执行 (第一个参数为映射的方法名)
- 调用executor的update方法(见2.2 Executor)
- 根据Configuration的ExecutorType执行器类型最终调用子方法的doUpdate方法,
- 再根据Configuration这个方法的MappedStatement构建Statement,Statement.update方法(见2.2 StatementHandler)
- 最终将sql做成数据包发送给服务器
INSTER
graph LR
mapper-interface --> MapperProxy.invoke --> 根据类型调用sqlSession的insert方法 --> 返回的结果类型为空并且存在结果处理器 --> 调用SqlSessionTemplate.insert方法 --> 调用默认实现的DefaultSqlSession的update方法 --> 调用executor.update --> 调用StatementHandler.update方法
- 将参数转换为Sql命令参数
- 调用sqlSession.insert(command.getName(), param)方法执行 (第一个参数为映射的方法名)
- sqlSession调用自己的update方法
- 调用executor的update方法(见2.2 Executor)
- 根据Configuration的ExecutorType执行器类型最终调用子方法的doUpdate方法,
- 再根据Configuration这个方法的MappedStatement构建Statement,Statement.update方法(见2.2 StatementHandler)
- 最终将sql做成数据包发送给服务器
DELETE
graph LR
mapper-interface --> MapperProxy.invoke --> 根据类型调用sqlSession的delete方法 --> 返回的结果类型为空并且存在结果处理器 --> 调用SqlSessionTemplate.delete方法 --> 调用默认实现的DefaultSqlSession的update方法 --> 调用executor.update --> 调用StatementHandler.update方法
- 将参数转换为Sql命令参数
- 调用sqlSession.delete(command.getName(), param)方法执行 (第一个参数为映射的方法名)
- sqlSession调用自己的update方法
- 调用executor的update方法(见2.2 Executor)
- 根据Configuration的ExecutorType执行器类型最终调用子方法的doUpdate方法,
- 再根据Configuration这个方法的MappedStatement构建Statement,Statement.update方法(见2.2 StatementHandler)
- 最终将sql做成数据包发送给服务器
入口类源码解析
1. 调用MapperProxy代理类
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
// 判断是否是Object的方法,如果是直接执行代理类方法
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
}
// 判断是不是默认方法(是公共的接口方法)
if (this.isDefaultMethod(method)) {
return this.invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable var5) {
throw ExceptionUtil.unwrapThrowable(var5);
}
// 在缓存列表中获取到代理方法 (如果没有缓存进行加载)
MapperMethod mapperMethod = this.cachedMapperMethod(method);
// 执行方法 (入参为sql上下文)
return mapperMethod.execute(this.sqlSession, args);
}
缓存方法
private MapperMethod cachedMapperMethod(Method method) {
// 判断缓存中是否存在该方法 如果没有 创建映射方法对象
MapperMethod mapperMethod = methodCache.get(method);
if (mapperMethod == null) {
mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
methodCache.put(method, mapperMethod);
}
return mapperMethod;
}
public MapperMethod(Class<?> mapperInterface, Method method, Configuration config){
// 构建 SQL 命令
this.command = new SqlCommand(config, mapperInterface, method);
// 构建 MethodSignature (方法签名)
this.method = new MethodSignature(config, mapperInterface, method);
}
构建 SQL 命令
public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
// 获取 方法名称
final String methodName = method.getName();
// 获取 方法的声明类
final Class<?> declaringClass = method.getDeclaringClass();
// 解析SQL语句
MappedStatement ms = resolveMappedStatement(mapperInterface, methodName, declaringClass,
configuration);
// 如果 映射陈述(MappedStatement)为空
if (ms == null) {
// 判断方法是否有 flush 注解 如果有 执行flush方法
if (method.getAnnotation(Flush.class) != null) {
name = null;
type = SqlCommandType.FLUSH;
} else {
// 否则 抛出 没有映射的异常
throw new BindingException("Invalid bound statement (not found): "+ mapperInterface.getName() + "." + methodName);
}
}
// 如果映射不为空
else {
// 获取到映射ID(方法名) 和 SQL 类型
name = ms.getId();
type = ms.getSqlCommandType();
if (type == SqlCommandType.UNKNOWN) {
throw new BindingException("Unknown execution method for: " + name);
}
}
}
private MappedStatement resolveMappedStatement(Class<?> mapperInterface, String methodName, Class<?> declaringClass, Configuration configuration) {
// 构建 陈述(缓存KEY)ID (方法全限定名)
String statementId = mapperInterface.getName() + "." + methodName;
// 判断配置中是否存在 缓存KEY (在启动的时候写入在 configuration.mappedStatements 中)
if (configuration.hasStatement(statementId)) {
// 如果有直接返回 如果没有返回 null
return configuration.getMappedStatement(statementId);
} else if (mapperInterface.equals(declaringClass)) {
return null;
}
// 获取父类(递归)
for (Class<?> superInterface : mapperInterface.getInterfaces()) {
if (declaringClass.isAssignableFrom(superInterface)) {
MappedStatement ms = resolveMappedStatement(superInterface, methodName,
declaringClass, configuration);
if (ms != null) {
return ms;
}
}
}
return null;
}
构建 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();
// 判断是否返回 光标(Cursor)
this.returnsCursor = Cursor.class.equals(this.returnType);
// 判断返回值是否为MAP(获取MAP 的 key)
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);
}
执行方法
public Object execute(SqlSession sqlSession, Object[] args) {
Object param;
Object result;
// 获取sql类型 (select update delete 还是 insert)
switch(this.command.getType()) {
case INSERT:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
break;
case UPDATE:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.update(this.command.getName(), param));
break;
case DELETE:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));
break;
case SELECT:
// 如果返回结果为void 并且 有结果处理程序 处理结构 之后 返回null
if (this.method.returnsVoid() && this.method.hasResultHandler()) {
this.executeWithResultHandler(sqlSession, args);
result = null;
// 如果返回的是集合类 执行:executeForMany
} else if (this.method.returnsMany()) {
result = this.executeForMany(sqlSession, args);
// 如果返回的是Map 执行:executeForMap
} else if (this.method.returnsMap()) {
result = this.executeForMap(sqlSession, args);
// 如果返回的是Cursor 执行:returnsCursor
} else if (this.method.returnsCursor()) {
result = this.executeForCursor(sqlSession, args);
} else {
// 将参数转换为Sql命令参数
param = this.method.convertArgsToSqlCommandParam(args);
// 最终执行sql上下文的方法
result = sqlSession.selectOne(this.command.getName(), param);
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + this.command.getName());
}
if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) {
throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ").");
} else {
return result;
}
}