发布于2026-07-01 阅读(0)
扫一扫,手机访问
很多时候我们不想在XML或接口里每写一个查询就声明一个方法,更希望有一个万能入口,直接传SQL字符串就能跑。其实不用那么麻烦,用注解就能搞定。XML的方式没测过,但思路应该大同小异。

1、先声明一个接口,里面放一个超级SQL方法:
public interface SqlDao{
@Select("${sql}")
List> sql(String sql,@Param("param") Map param);
}
2、调用的时候就像这样:
Mapparams = new HashMap<>(); //这里可加任意多参数,与SQL中对应 params.put("id","xxx"); List > result = medicineboxDao.sql("select * from DevLog where id =#{param.id}",params);
返回的是通用的Map类型,够灵活,但要是想直接拿到业务实体对象,就得自己再转一次。于是有了下一步改进的念头。
给接口方法加上泛型,期望通过泛型参数自动映射到具体的实体类型,结果却踩了个坑——代码跑起来居然不报错,但结果就让人摸不着头脑了。代码如下:
1、先把接口方法改成泛型:
public interface SqlDao{
@Select("${sql}")
List sql2(String sql,@Param("param") Map param);
}
//调用
List o2 = medicineboxDao.sql2("select * from DevLog where id =#{param.id}",params);
执行不报错,但返回的结果集明明有多个记录,实际上只拿到了一条数据,而且这条数据里只有第一个字段的值。更诡异的是,当你试图获取集合里元素的类型时:
//System.out.println(o2.get(0).getClass()); // 一运行就报类转换异常
可惜没深入跟过MyBatis的源码,猜测是MyBatis没法根据泛型参数自动推断返回类型,结果封装时出了问题。这个坑留给大家验证。
既然直接泛型走不通,那就绕一下——用 default 方法 + ResultHandler 手动转换。代码如下:
@Select({"${sql}"})
default List sqlFromObject(String sql,@Param("param") Map param,Class sc){
final List lis = new ArrayList<>();
this.generalSql(sql, param, (ResultHandler) resultContext -> {
try {
S s = sc.newInstance();
//采用cglib BeanCopier,性能强劲
//bean map拷贝
BeanMap beanMap = BeanMap.create(s);
beanMap.putAll((Map)resultContext.getResultObject());
lis.add(s);
} catch (Exception e) {
e.printStackTrace();
}
});
return lis;
};
@Select({"${sql}"})
@ResultType(LinkedHashMap.class)
void generalSql(String sql, @Param("param") Map param, ResultHandler handler) ;
调用方式也变得清晰了:
Listo2 = medicineboxDao.sqlFromObject("select * from DevLog where id <>#{param.id}",params,DevLog.class);
这样就能直接拿到 List,而且每一条数据里的字段都映射到了对应的属性上。用起来还算顺手。
以上就是基于实际项目的一些实践思路:先提供一个简单的万能SQL接口对付临时查询,再尝试泛型自动映射但发现MyBatis对泛型返回值支持有限,最后用 default 方法手工转换绕过了这个限制。如果你也有类似需求,可以参考这个方案。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8