Mybatis源码解析之写流程

阅读须知

  • Mybatis源码版本:3.4.4
  • 文章中使用/* */注释的方法会做深入分析

正文

承接上文,我们继续来分析写操作:
DefaultSqlSession:

public int insert(String statement, Object parameter) {
	return update(statement, parameter);
}

DefaultSqlSession:

public int update(String statement, Object parameter) {
	try {
		dirty = true;
		// 获取MappedStatement
		MappedStatement ms = configuration.getMappedStatement(statement);
		/* 包装集合类型的参数(分析查询流程时已经分析过),执行更新操作 */
		return executor.update(ms, wrapCollection(parameter));
	} catch (Exception e) {
		throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);
	} finally {
		ErrorContext.instance().reset();
	}
}

DefaultSqlSession:

public int delete(String statement, Object parameter) {
	return update(statement, parameter);
}

我们发现insert、update、delete三个方法最终都调用了同一个update方法。
CachingExecutor:

public int update(MappedStatement ms, Object parameterObject) throws SQLException {
	flushCacheIfRequired(ms); // 如果需要,刷新缓存
	/* 更新操作 */
	return delegate.update(ms, parameterObject);
}

Mybatis缓存我们会用单独的文章来分析。
BaseExecutor:

public int update(MappedStatement ms, Object parameter) throws SQLException {
	ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
	if (closed) {
		throw new ExecutorException("Executor was closed.");
	}
	clearLocalCache(); // 清除本地缓存
	return doUpdate(ms, parameter); /* 执行更新操作 */
}

SimpleExecutor:

public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
	Statement stmt = null;
	try {
		Configuration configuration = ms.getConfiguration();
		// 创建StatementHandler(分析查询流程时已经分析过)
		StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
		// 准备Statement(分析查询流程时已经分析过)
		stmt = prepareStatement(handler, ms.getStatementLog());
		return handler.update(stmt); /* 更新操作 */
	} finally {
		closeStatement(stmt); // 关闭Statement
	}
}

PreparedStatementHandler:

public int update(Statement statement) throws SQLException {
	PreparedStatement ps = (PreparedStatement) statement;
	ps.execute(); // 执行sql命令
	int rows = ps.getUpdateCount(); // 返回影响的行数
	Object parameterObject = boundSql.getParameterObject();
	KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
	/* KeyGenerator后置处理(前置处理在创建StatementHandler时应用) */
	keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
	return rows;
}

我们以SelectKeyGenerator来分析KeyGenerator的后置处理:
SelectKeyGenerator:

public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
	if (!executeBefore) { // 如果不是前置处理
		/* 处理生成的key */
		processGeneratedKeys(executor, ms, parameter);
	}
}

分析之前我们可以先回想一下<selectkey/>标签的应用,有助于理解下面的处理过程。
SelectKeyGenerator:

private void processGeneratedKeys(Executor executor, MappedStatement ms, Object parameter) {
	try {
		if (parameter != null && keyStatement != null && keyStatement.getKeyProperties() != null) {
			String[] keyProperties = keyStatement.getKeyProperties(); // 获取配置的目标属性
			final Configuration configuration = ms.getConfiguration();
			final MetaObject metaParam = configuration.newMetaObject(parameter);
			if (keyProperties != null) {
				// 新建执行器
				Executor keyExecutor = configuration.newExecutor(executor.getTransaction(), ExecutorType.SIMPLE);
				// 执行查询
				List<Object> values = keyExecutor.query(keyStatement, parameter, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
				// 返回结果集长度的校验
				if (values.size() == 0) {
					throw new ExecutorException("SelectKey returned no data.");            
				} else if (values.size() > 1) {
					throw new ExecutorException("SelectKey returned more than one value.");
				} else {
					MetaObject metaResult = configuration.newMetaObject(values.get(0));
					// 如果只设置了单个目标属性直接赋值
					if (keyProperties.length == 1) {
						if (metaResult.hasGetter(keyProperties[0])) {
							setValue(metaParam, keyProperties[0], metaResult.getValue(keyProperties[0]));
						} else {
							setValue(metaParam, keyProperties[0], values.get(0));
						}
					} else {
						/* 设置多个目标属性的处理 */
						handleMultipleProperties(keyProperties, metaParam, metaResult);
					}
				}
			}
		}
	} catch (ExecutorException e) {
		throw e;
	} catch (Exception e) {
		throw new ExecutorException("Error selecting key or setting result to parameter object. Cause: " + e, e);
	}
}

SelectKeyGenerator:

private void handleMultipleProperties(String[] keyProperties,
	MetaObject metaParam, MetaObject metaResult) {
	String[] keyColumns = keyStatement.getKeyColumns();
	if (keyColumns == null || keyColumns.length == 0) {
		// 没有指定具体的列,直接使用属性名称赋值
		for (String keyProperty : keyProperties) {
			setValue(metaParam, keyProperty, metaResult.getValue(keyProperty));
		}
	} else {
		// 指定列的数量与属性的数量不相等抛出异常
		if (keyColumns.length != keyProperties.length) {
			throw new ExecutorException("If SelectKey has key columns, the number must match the number of key properties.");
		}
		for (int i = 0; i < keyProperties.length; i++) {
			// 使用列名赋值
			setValue(metaParam, keyProperties[i], metaResult.getValue(keyColumns[i]));
		}
	}
}

最后是对返回影响行数的处理:

private Object rowCountResult(int rowCount) {
	final Object result;
	// 根据方法返回值类型将影响行数转换成对应的类型
	if (method.returnsVoid()) {
		result = null;
	} else if (Integer.class.equals(method.getReturnType()) || Integer.TYPE.equals(method.getReturnType())) {
		result = rowCount;
	} else if (Long.class.equals(method.getReturnType()) || Long.TYPE.equals(method.getReturnType())) {
		result = (long)rowCount;
	} else if (Boolean.class.equals(method.getReturnType()) || Boolean.TYPE.equals(method.getReturnType())) {
		result = rowCount > 0;
	} else {
		throw new BindingException("Mapper method '" + command.getName() + "' has an unsupported return type: " + method.getReturnType());
	}
	return result;
}

到这里,Mybatis写操作的源码分析就完成了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值