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写操作的源码分析就完成了。
相关文章推荐
- mybatis源码解析 - 通过一个简单查询例子分析流程
- Mybatis源码详解之接口方法被执行流程源码解析
- MyBatis源码解析(一)——执行流程
- mybatis源码解析-----执行流程1
- Mybatis源码解析之查询流程
- Mybatis的源码与流程解析
- mybatis源码解析 - 通过一个简单查询例子分析流程
- mybatis源码解析以及执行的流程
- Tomcat源码解析-整体流程介绍
- MyBatis源码解析(一)——MyBatis初始化过程解析
- MyBatis-3.4.2-源码分析2:解析XML之settingsAsProperties(root.evalNode("settings"))
- Kernel启动流程源码解析 4 start_kernel 上
- Mybatis 源码之Plugin类解析
- mybatis源码解析(三)-SqlSession.selectOne类似方法调用过程
- Mybatis SqlSessionTemplate 源码解析
- Mybatis源码解析
- (三)MyBatis源码解析之配置文件
- Android Activity启动流程源码解析
- spring、mybatis加载xml源码解析
- Kernel启动流程源码解析 7 rest_init()