MapperMethod

  • Author: HuiFer
  • Description: 该文介绍 mybatis MapperMethod 源码
  • 源码地址: org.apache.ibatis.binding.MapperMethod,核心方法是execute
  • 源码阅读工程: SourceHot-Mybatis
  1. /**
  2. * CRUD 不同的执行处理
  3. *
  4. * @param sqlSession
  5. * @param args
  6. * @return
  7. */
  8. public Object execute(SqlSession sqlSession, Object[] args) {
  9. Object result;
  10. switch (command.getType()) {
  11. case INSERT: {
  12. Object param = method.convertArgsToSqlCommandParam(args);
  13. result = rowCountResult(sqlSession.insert(command.getName(), param));
  14. break;
  15. }
  16. case UPDATE: {
  17. Object param = method.convertArgsToSqlCommandParam(args);
  18. result = rowCountResult(sqlSession.update(command.getName(), param));
  19. break;
  20. }
  21. case DELETE: {
  22. Object param = method.convertArgsToSqlCommandParam(args);
  23. result = rowCountResult(sqlSession.delete(command.getName(), param));
  24. break;
  25. }
  26. case SELECT:
  27. if (method.returnsVoid() && method.hasResultHandler()) {
  28. executeWithResultHandler(sqlSession, args);
  29. result = null;
  30. } else if (method.returnsMany()) {
  31. result = executeForMany(sqlSession, args);
  32. } else if (method.returnsMap()) {
  33. result = executeForMap(sqlSession, args);
  34. } else if (method.returnsCursor()) {
  35. result = executeForCursor(sqlSession, args);
  36. } else {
  37. Object param = method.convertArgsToSqlCommandParam(args);
  38. result = sqlSession.selectOne(command.getName(), param);
  39. if (method.returnsOptional()
  40. && (result == null || !method.getReturnType().equals(result.getClass()))) {
  41. result = Optional.ofNullable(result);
  42. }
  43. }
  44. break;
  45. case FLUSH:
  46. result = sqlSession.flushStatements();
  47. break;
  48. default:
  49. throw new BindingException("Unknown execution method for: " + command.getName());
  50. }
  51. if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
  52. throw new BindingException("Mapper method '" + command.getName()
  53. + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
  54. }
  55. return result;
  56. }
  1. /**
  2. * 根据 resultHandler 进行处理
  3. *
  4. * @param sqlSession
  5. * @param args
  6. */
  7. private void executeWithResultHandler(SqlSession sqlSession, Object[] args) {
  8. MappedStatement ms = sqlSession.getConfiguration().getMappedStatement(command.getName());
  9. if (!StatementType.CALLABLE.equals(ms.getStatementType())
  10. && void.class.equals(ms.getResultMaps().get(0).getType())) {
  11. throw new BindingException("method " + command.getName()
  12. + " needs either a @ResultMap annotation, a @ResultType annotation,"
  13. + " or a resultType attribute in XML so a ResultHandler can be used as a parameter.");
  14. }
  15. Object param = method.convertArgsToSqlCommandParam(args);
  16. // 判断是否有 RowBounds
  17. if (method.hasRowBounds()) {
  18. RowBounds rowBounds = method.extractRowBounds(args);
  19. sqlSession.select(command.getName(), param, rowBounds, method.extractResultHandler(args));
  20. } else {
  21. sqlSession.select(command.getName(), param, method.extractResultHandler(args));
  22. }
  23. }
  • 返回值为多个的情况
  1. /**
  2. * 针对多个查询结果进行 ,转换成不同的 list 或者数组
  3. *
  4. * @param sqlSession
  5. * @param args
  6. * @param <E>
  7. * @return
  8. */
  9. private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
  10. List<E> result;
  11. Object param = method.convertArgsToSqlCommandParam(args);
  12. if (method.hasRowBounds()) {
  13. RowBounds rowBounds = method.extractRowBounds(args);
  14. // 直接 list
  15. result = sqlSession.selectList(command.getName(), param, rowBounds);
  16. } else {
  17. result = sqlSession.selectList(command.getName(), param);
  18. }
  19. // issue #510 Collections & arrays support
  20. if (!method.getReturnType().isAssignableFrom(result.getClass())) {
  21. if (method.getReturnType().isArray()) {
  22. // 转换成 array
  23. return convertToArray(result);
  24. } else {
  25. // 转换成 collection
  26. return convertToDeclaredCollection(sqlSession.getConfiguration(), result);
  27. }
  28. }
  29. return result;
  30. }

convertToArray

  1. /**
  2. * 转换为数组
  3. *
  4. * @param list 数据库查询结果
  5. * @param <E>
  6. * @return
  7. */
  8. @SuppressWarnings("unchecked")
  9. private <E> Object convertToArray(List<E> list) {
  10. // 获取返回类型
  11. Class<?> arrayComponentType = method.getReturnType().getComponentType();
  12. // new 一个 array
  13. Object array = Array.newInstance(arrayComponentType, list.size());
  14. if (arrayComponentType.isPrimitive()) {
  15. for (int i = 0; i < list.size(); i++) {
  16. Array.set(array, i, list.get(i));
  17. }
  18. return array;
  19. } else {
  20. // 通过 toArray方法转换
  21. return list.toArray((E[]) array);
  22. }
  23. }

convertToDeclaredCollection

  1. /**
  2. * 转换为不同的list对象
  3. *
  4. * @param config
  5. * @param list 数据库查询结果
  6. * @param <E>
  7. * @return
  8. */
  9. private <E> Object convertToDeclaredCollection(Configuration config, List<E> list) {
  10. // mybatis ObjectFactory 创建mapper 的返回结果对象
  11. Object collection = config.getObjectFactory().create(method.getReturnType());
  12. MetaObject metaObject = config.newMetaObject(collection);
  13. // metaObject.objectWrapper => CollectionWrapper
  14. // MetaObject 对象的 objectWrapper 现在是 CollectionWrapper 它是 Collection 的包装
  15. metaObject.addAll(list);
  16. return collection;
  17. }
  • 上述两个为转换的过程,其实质还是在 org.apache.ibatis.session.SqlSession 中做执行操作

debug

  • 修改 mapper 返回数组对org.apache.ibatis.binding.MapperMethod#convertToArray方法进行测试
  1. HsSell[] list(@Param("ID") Integer id);

image-20191219092442456

  • 修改 mapper,对org.apache.ibatis.binding.MapperMethod#convertToDeclaredCollection进行测试

    1. LinkedList<HsSell> list(@Param("ID") Integer id);

image-20191219093043035