手写MyBatis第16弹:泛型魔法应用:MyBatis如何破解List的运行时类型

发布于:2025-08-15 ⋅ 阅读:(15) ⋅ 点赞:(0)

结果映射的起点:MyBatis如何预知你的返回类型

  1. 《MyBatis未卜先知?解析Mapper方法返回类型的黑科技》

  2. 《从List到POJO:MyBatis结果集类型推断全揭秘》

  3. 《手写MyBatis结果映射第一步:捕获方法返回类型》

  4. 《泛型魔法:MyBatis如何破解List的运行时类型》

  5. 《返回类型决定结果处理:MyBatis的ORM类型系统设计》


结果映射的起点:MyBatis如何预知你的返回类型

引言: 当MyBatis执行selectById方法时,它如何预知应该将结果集转换为User对象还是List?本文将深入解析MyBatis获取方法返回类型的核心机制,以及这对后续结果处理的关键影响。


一、返回类型获取的两种方式

1. 基础类型获取
 // 获取简单返回类型
 Class<?> returnType = method.getReturnType();
 ​
 // 示例方法:User selectById(int id);
 // returnType == User.class
2. 泛型类型解析
 // 获取泛型返回类型
 Type genericReturnType = method.getGenericReturnType();
 ​
 // 示例方法:List<User> selectAll();
 if (genericReturnType instanceof ParameterizedType) {
     ParameterizedType pt = (ParameterizedType) genericReturnType;
     Type[] actualTypeArgs = pt.getActualTypeArguments();
     Class<?> elementType = (Class<?>) actualTypeArgs[0];
     // elementType == User.class
 }

二、MappedStatement的类型存储

1. 返回类型封装
public class MappedStatement {
     private Class<?> resultType;
     private Class<?> resultMapClass; // 复杂映射
     private boolean returnsList;
     
     public static class Builder {
         public Builder(Method method) {
             // 解析返回类型
             Type returnType = method.getGenericReturnType();
             
             // 处理集合类型
             if (returnType instanceof ParameterizedType 
                 && List.class.isAssignableFrom(method.getReturnType())) {
                 this.returnsList = true;
                 Type elementType = ((ParameterizedType)returnType).getActualTypeArguments()[0];
                 this.resultType = (Class<?>) elementType;
             } 
             // 处理普通类型
             else {
                 this.resultType = method.getReturnType();
             }
         }
     }
 }
2. 类型推断流程图


三、六类返回类型的处理策略

返回类型 处理方式 示例 特殊说明
void 不处理结果集 void deleteById() 通常用于更新操作
基本类型 单行单列 int count() 自动拆箱处理
POJO 属性映射 User selectById() 最常见场景
List 多行映射 List<User> selectAll() 自动识别元素类型
Map 列名-值对 Map<String,Object> selectAsMap() 键为列名/别名
Cursor 流式处理 Cursor<User> scroll() 需要手动关闭

四、泛型类型解析的三种技巧

1. 常规泛型解析
 // 解析List<User>
 Type returnType = method.getGenericReturnType();
 if (returnType instanceof ParameterizedType) {
     ParameterizedType pt = (ParameterizedType) returnType;
     Type rawType = pt.getRawType(); // List.class
     Type[] typeArgs = pt.getActualTypeArguments(); // [User.class]
 }
2. 嵌套泛型处理
 // 解析Map<String,List<User>>
 if (typeArgs[1] instanceof ParameterizedType) {
     ParameterizedType nestedPt = (ParameterizedType) typeArgs[1];
     Type[] nestedArgs = nestedPt.getActualTypeArguments();
 }
3. 类型变量处理
// 处理泛型方法<T> T selectById()
 if (returnType instanceof TypeVariable) {
     // 通常需要从参数或注解获取实际类型
     returnType = getActualTypeFromAnnotation(method);
 }

五、ResultSet元数据的关键作用

元数据与类型系统的协作

元数据的三重价值:
  1. 列名匹配:将user_name列映射到userName字段

  2. 类型转换:将SQL的TIMESTAMP转为Java的Date

  3. 结果验证:检查返回列数与对象属性匹配情况


六、ResultHandler的扩展能力

自定义结果处理示例
public interface ResultHandler<T> {
     void handleResult(ResultContext<? extends T> resultContext);
 }
 ​
 // 示例:批量处理结果
 public class BatchResultHandler implements ResultHandler<User> {
     private final List<User> batch = new ArrayList<>();
     
     @Override
     public void handleResult(ResultContext<? extends User> context) {
         batch.add(context.getResultObject());
         if (batch.size() >= 1000) {
             processBatch(batch);
             batch.clear();
         }
     }
 }
使用场景对比
场景 直接返回 ResultHandler
大数据集 内存压力大 流式处理
复杂转换 需二次处理 实时转换
过程监控 无法感知 获取处理统计

七、企业级实践建议

1. 安全类型检查
 public void validateReturnType(Method method) {
     Class<?> type = method.getReturnType();
     if (Void.TYPE.equals(type) && isSelectStatement(method)) {
         throw new RuntimeException("查询方法不应返回void");
     }
 }
2. 智能类型推导
 public Class<?> inferElementType(Method method) {
     // 从@ResultType注解获取
     ResultType anno = method.getAnnotation(ResultType.class);
     if (anno != null) return anno.value();
     
     // 从方法参数推导
     if (hasTypeParameter(method)) {
         return extractFromGenericSignature(method);
     }
     
     // 默认Object
     return Object.class;
 }
3. 性能优化缓存
 private static final Map<Method, Class<?>> RETURN_TYPE_CACHE = new ConcurrentHashMap<>();
 ​
 public Class<?> getCachedReturnType(Method method) {
     return RETURN_TYPE_CACHE.computeIfAbsent(method, m -> {
         Type type = m.getGenericReturnType();
         return parseActualType(type);
     });
 }

结语: 返回类型的准确获取是MyBatis结果映射的基石,从简单的POJO到复杂的泛型集合,类型系统的完善设计保证了ORM转换的精确性。理解这一机制,不仅能更好地使用MyBatis,也为实现自定义结果处理器打下了坚实基础。