结果映射的起点:MyBatis如何预知你的返回类型
《MyBatis未卜先知?解析Mapper方法返回类型的黑科技》
《从List到POJO:MyBatis结果集类型推断全揭秘》
《手写MyBatis结果映射第一步:捕获方法返回类型》
《泛型魔法:MyBatis如何破解List的运行时类型》
《返回类型决定结果处理: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元数据的关键作用
元数据与类型系统的协作
元数据的三重价值:
列名匹配:将
user_name
列映射到userName
字段类型转换:将SQL的
TIMESTAMP
转为Java的Date
结果验证:检查返回列数与对象属性匹配情况
六、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,也为实现自定义结果处理器打下了坚实基础。