在使用MyBatis作为Java项目的ORM框架时,在Mapper接口中传递参数需要通过@Param
注解指定参数名称,这样才能在Mapper接口对应的xml文件中引用到对应名称的参数。如果不在Mapper接口中明确使用@Param
注解时将会报错:找不到指定名称的参数
。
追根溯源,这要从MyBatis获取Mapper接口参数名的实现说起,如下源码:
// ParamNameResolver.java
// 在ParamNameResolver构造函数中获取Mapper接口参数的实现思路如下:
// 1.如果参数使用注解@Param,则取注解值作为参数名;
// 2.如果参数未使用注解@Param,就尝试通过反射方式获取Mapper接口的参数名;
// 3.如果在第2步仍然未获取到参数名,则使用参数索引值(如:0,1,2....)作为参数名;
public ParamNameResolver(Configuration config, Method method) {
this.useActualParamName = config.isUseActualParamName();
final Class<?>[] paramTypes = method.getParameterTypes();
final Annotation[][] paramAnnotations = method.getParameterAnnotations();
final SortedMap<Integer, String> map = new TreeMap<>();
int paramCount = paramAnnotations.length;
// get names from @Param annotations
for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) {
if (isSpecialParameter(paramTypes[paramIndex])) {
// skip special parameters
continue;
}
String name = null;
for (Annotation annotation : paramAnnotations[paramIndex]) {
if (annotation instanceof Param) {
hasParamAnnotation = true;
name = ((Param) annotation).value();
break;
}
}
if (name == null) {
// @Param was not specified.
if (useActualParamName) {
name = getActualParamName(method, paramIndex);
}
if (name == null) {
// use the parameter index as the name ("0", "1", ...)
// gcode issue #71
name = String.valueOf(map.size());
}
}
map.put(paramIndex, name);
}
names = Collections.unmodifiableSortedMap(map);
}
// 通过注解方式获取Mapper参数名
private String getActualParamName(Method method, int paramIndex) {
return ParamNameUtil.getParamNames(method).get(paramIndex);
}
// ParamNameUtil.java
public class ParamNameUtil {
public static List<String> getParamNames(Method method) {
return getParameterNames(method);
}
public static List<String> getParamNames(Constructor<?> constructor) {
return getParameterNames(constructor);
}
// 这里依赖Java编译器在编译代码时是否保留了参数的实际名称,如果未保留参数实际名称则返回null
private static List<String> getParameterNames(Executable executable) {
return Arrays.stream(executable.getParameters()).map(Parameter::getName).collect(Collectors.toList());
}
private ParamNameUtil() {
super();
}
}
综上所述,在MyBatis框架的Mapper接口中是否需要使用注解@Param
明确指定参数名称,依赖Java编译器在编译代码时是否保留了方法参数的实际名称。
那么问题就转变成了:Java编译器在什么时候会保留方法参数的实际名称呢?依赖2个条件:
1.JDK版本必须是8及以上,参见:java8中新增编译参数parameters入门,jdk1.8 开启-parameters参数,编译保留参数名,为反射提供便利。
2.在Maven插件maven-compiler-plugin
中明确设置编译参数,根据插件版本不同,设置编译参数的方式各异,如下:
版本3.6.2之前
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.6.0</version> <configuration> <!-- 添加编译JDK8+支持的编译参数-parameters,保留方法参数名称 --> <compilerArgs>-parameters</compilerArgs> </configuration> </plugin>
版本3.6.2及之后
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.6.0</version> <configuration> <!-- 添加编译JDK8+支持的编译参数-parameters,保留方法参数名称 --> <parameters>true</parameters> </configuration> </plugin>
当然,在IDEA中运行代码时,如果没有明确配置maven-compiler-plugin
插件的编译参数,还可以设置项目模块的编译参数,如下:
【参考】
MyBatis多参数传递之@Param究竟加还是不加?
关于Mybatis的@Param注解
Mybatis省略@Param注解原理
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达,在下面评论区告诉我^_^^_^