使用MyBatis框架时Mapper传参是否需要使用@Param注解

在使用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注解原理

posted @   nuccch  阅读(40)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示