2019独角兽企业重金招聘Python工程师标准>>>
由前面的系列二分析到MapperMethod的execute方法,我们接着分析MapperMethod。如下List-1:
List-1
public class MapperMethod {private final SqlCommand command;private final MethodSignature method;public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {this.command = new SqlCommand(config, mapperInterface, method);this.method = new MethodSignature(config, mapperInterface, method);}public Object execute(SqlSession sqlSession, Object[] args) {Object result;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 {Object param = method.convertArgsToSqlCommandParam(args);result = sqlSession.selectOne(command.getName(), param);}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;}
...
List-1中,根据类型来调用不同的处理,我们以insert为例子分析,调用的就是如下的List-2,首先将传入Mapper方法上的参数转换为SQL参数,之后调用SqlSession的insert方法,注意这个SqlSession是SqlSessionTemplate,我们来看SqlSessionTemplate的insert方法,如List-3:
List-2
case INSERT: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.insert(command.getName(), param));break;
}
List-3
public int insert(String statement, Object parameter) {return this.sqlSessionProxy.insert(statement, parameter);
}
如下图1所示,
图1
- 步骤2调用的SqlSessionInterceptor是JDK的代理类;
- 步骤4中,做了很多事情,比如不同类型Executor的生成就是在里面;
- 步骤13中,会先清空缓存——因为我们目前看的是insert更新操作;
- 步骤17中调用的StatementHandler默认是RoutingStatementHandler,用了Delegate设计模式,默认情况下委托给PreparedStatementHandler;
- 步骤23中,涉及了KeyGenerator,所以后面看mybatis中返还主键值看这里;
步骤17中,RoutingStatementHandler使用了代理模式,将事情全部委托给第三方来做。
步骤1中调用的SqlSessionTemplate,以Template结尾,看着像使用Template模板模式,但是个人觉得是使用了代理模式,因为它内部实现上,大部分事情都委托给了内部类SqlSessionInterceptor。
值得一提的是,BaseExecutor使用了Template模板模式,定义了执行步骤,然后具体实现由其实现类了实现。
图1的过程中,涉及了事物,使用的是Spring的事物管理。