MyBatis源码分析之——执行SQL语句的过程

User user = userMapper.getUserById(1)

调用invoke代理方法

由于所有的 Mapper 都是 MapperProxy 代理对象,所以任意的方法都是执行MapperProxy 的invoke()方法。

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
	//判断是否需要去执行SQL还是直接执行方法
	if (Object.class.equals(method.getDeclaringClass())) {
		return method.invoke(this, args);
		//这里判断的是接口中的默认方法Default等
	} else if (isDefaultMethod(method)) {
		return invokeDefaultMethod(proxy, method, args);
	}
} catch (Throwable t) {
	throw ExceptionUtil.unwrapThrowable(t);
}
//获取缓存,保存了方法签名和接口方法的关系
final MapperMethod mapperMethod = cachedMapperMethod(method);
	return mapperMethod.execute(sqlSession, args);
}

调用execute方法

咱们的例子用的是查询所以走的是else。

public Object execute(SqlSession sqlSession, Object[] args) {
	Object result;
	//根据命令类型走不行的操作command.getType()是select
	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 {
				//将参数转换为SQL的参数
				Object param = method.convertArgsToSqlCommandParam(args);
				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;
}

调用selectOne其实是selectList

selectone查询一个和查询多个其实是一样的

public  T selectOne(String statement, Object parameter) {
	// Popular vote was to return null on 0 results and throw exception on too many.
	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;
	}
}
public  List selectList(String statement, Object parameter, RowBounds rowBounds) {
	try {
		//从Configuration里的mappedStatements里根据key(id的全路径)获取MappedStatement对象
		MappedStatement ms = configuration.getMappedStatement(statement);
		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();
	}
}

mappedStatements对象如图

MyBatis源码分析之——执行SQL语句的过程_第1张图片

MappedStatement对象如图

MyBatis源码分析之——执行SQL语句的过程_第2张图片

执行query方法

1.创建CacheKey

从 BoundSql 中获取SQL信息,创建 CacheKey。这个CacheKey就是缓存的Key。

public  List query(MappedStatement ms, Object parameterObject, RowBounds
rowBounds, ResultHandler resultHandler) throws SQLException {
	//创建缓存Key
	BoundSql boundSql = ms.getBoundSql(parameterObject);
	//key = -575461213:-771016147:mapper.UserMapper.getUserById:0:2147483647:select * from test_user where id = ?:1:development
	CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
	return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
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, boundSql);
			@SuppressWarnings("unchecked")
			List list = (List) 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;
		}
	} 
	return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

2.清空本地缓存

public  List query(MappedStatement ms, Object parameter, RowBounds
rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
	ErrorContext.instance().resource(ms.getResource()).activity("executing aquery").object(ms.getId());
	if (closed) {
		throw new ExecutorException("Executor was closed.");
	}
	//queryStack 用于记录查询栈,防止递归查询重复处理缓存
	//flushCache=true 的时候,会先清理本地缓存(一级缓存)
	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 {
			//如果没有缓存,会从数据库查询:queryFromDatabase()
			list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
		}
	} finally {
		queryStack--;
	} 
	if (queryStack == 0) {
		for (DeferredLoad deferredLoad : deferredLoads) {
			deferredLoad.load();
		} 
		// issue #601
		deferredLoads.clear();
		//如果 LocalCacheScope == STATEMENT,会清理本地缓存
		if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
			// issue #482
			clearLocalCache();
		}
	} 
	return list;
}

3.从数据库查询

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 {
		//执行Executor 的 doQuery(),默认是SimpleExecutor
		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

public  List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, 
ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
	Statement stmt = null;
	try {
		Configuration configuration = ms.getConfiguration();
		StatementHandler handler = configuration.newStatementHandler(wrapper, ms,
		parameter, rowBounds, resultHandler, boundSql);
		stmt = prepareStatement(handler, ms.getStatementLog());
		return handler.query(stmt, resultHandler);
	} finally {
		closeStatement(stmt);
	}
}

 

你可能感兴趣的:(MyBatis)