您的位置:首页 > 其它

Mybatis源码解析之写流程

2018-01-21 18:20 337 查看

阅读须知

Mybatis源码版本:3.4.4

注释规则:

//单行注释做普通注释

/**/多行注释做深入分析

建议配合Mybatis源码阅读

正文

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

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写操作的源码分析就完成了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: