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

LD is tigger forever,CG are not brothers forever, throw the pot and shine forever.
Modesty is not false, solid is not naive, treacherous but not deceitful, stay with good people, and stay away from poor people.
talk is cheap, show others the code,Keep progress,make a better result.
Survive during the day and develop at night。

目录

概 述

原理概述

由于所有的 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);
}

调用exeute方法:

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> 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.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;
	}
}
selectList
public <E> List<E> 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();
	}
}

执行query方法:

相关工具如下:

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

public <E> List<E> 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 <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;
		}
	} 
	return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

2.清空缓存

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 aquery").object(ms.getId());
	if (closed) {
		throw new ExecutorException("Executor was closed.");
	}
	//queryStack 用于记录查询栈,防止递归查询重复处理缓存
	//flushCache=true 的时候,会先清理本地缓存(一级缓存)
	if (queryStack == 0 && ms.isFlushCacheRequired()) {
		//清空本地缓存
		clearLocalCache();
	} 
	List<E> list;
	try {
		queryStack++;
		list = resultHandler == null ? (List<E>) 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 <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 {
		//执行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;
}

分析:

小结:

主要讲述了MyBatis源码分析之——执行SQL语句的过程,请大家指正~

参考资料和推荐阅读

1.链接: 参考资料.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

执于代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值