由前面的系列二分析到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的事物管理。