首页 > 解决方案 > 选择提供者 Mybatis 错误:找不到参数 'arg0'。可用参数为 [productAttributeDto, param1]

问题描述

我正在将 Mybatis 与 Spring Boot 应用程序一起使用。我曾经使用 ProviderMethodResolver 生成 MySql 查询的地方。我的应用程序支持 mybatis 注解处理器和 XML 处理器。

为了实现这一点,我使用了这个 Mybatis 配置:

在 appication.properties 文件中

mybatis.mapper-locations=classpath*:/repository/**/*Repository.xml

和一个 MybatisConfiguration.java

@Configuration
@EnableTransactionManagement
public class MybatisConfiguration {

    @Bean
    ConfigurationCustomizer mybatisConfigurationCustomizer() {
        return new ConfigurationCustomizer() {
            @Override
            public void customize(org.apache.ibatis.session.Configuration configuration) {
                configuration.setMapUnderscoreToCamelCase(true);
                configuration.setCacheEnabled(true);
            }
        };
    }
}

使用上述配置,一切(@Select, @Insert, @ResultMap)似乎工作正常,除了@SelectProvider.

SelectProvider 实现是

VariantRepository.java

@Mapper
public interface VariantRepository {

    @SelectProvider(type = VariantSqlProvider.class, method = "getProductAttribute")
    VariantDto findByProductAttribute(@Param("productAttributeDto") ProductAttributeDto productAttributeDto);
}

我在用org.apache.ibatis.annotations.Param

ProductAttributeDto.java

@Data
public class ProductAttributeDto {

    private Integer productId;

    Map<String, String> attributes;
}

VariantSqlProvider.class

  public class VariantSqlProvider implements ProviderMethodResolver {

    @SuppressWarnings("unused")
    public static String getProductAttribute(final ProductAttributeDto productAttributeDto) {
        return new SQL() {{
            SELECT("*");
            FROM("ec_product_variant AS pv");
            if (Objects.nonNull(productAttributeDto.getAttributes())) {
                for (Entry<String, String> entry : productAttributeDto.getAttributes().entrySet()) {
                    if(Objects.nonNull(entry.getValue())) {
                        INNER_JOIN(
                                new StringBuilder("ec_attributes AS ")
                                .append(entry.getKey())
                                .append(" ON ")
                                .append(entry.getKey()).append(".id = pv.").append(entry.getKey())
                                .append(" AND ")
                                .append(entry.getKey()).append(".value=#{productAttributeDto.attributes.").append(entry.getKey())
                                .append("}").toString()
                        );
                    } else {
                        WHERE("pv." + entry.getKey() + " IS NULL");
                    }
                }
            }
            if(Objects.nonNull(productAttributeDto.getProductId())) {
                WHERE("pv.product_id = #{productAttributeDto.productId}");
            }
        }}.toString();
    }
}

当我调用该findByProductAttribute方法时,我收到这样的错误

org.apache.juli.logging.DirectJDKLog: Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.builder.BuilderException: Error invoking SqlProvider method 'public static java.lang.String com.ecommerce.app.repository.product.sqlprovider.VariantSqlProvider.getProductAttribute(com.ecommerce.app.model.product.ProductAttributeDto)' with specify parameter 'class org.apache.ibatis.binding.MapperMethod$ParamMap'.  Cause: org.apache.ibatis.binding.BindingException: Parameter 'arg0' not found. Available parameters are [productAttributeDto, param1]] with root cause
org.apache.ibatis.binding.BindingException: Parameter 'arg0' not found. Available parameters are [productAttributeDto, param1]
        at org.apache.ibatis.binding.MapperMethod$ParamMap.get(MapperMethod.java:212)
        at org.apache.ibatis.builder.annotation.ProviderSqlSource.extractProviderMethodArguments(ProviderSqlSource.java:223)

我期望生成的 SQL 查询是:

SELECT *
FROM ec_product_variant AS pv 
INNER JOIN ec_attributes AS color ON color.id = pv.color AND color.value=? 
WHERE (pv.size IS NULL AND pv.product_id = ?)

该查询基于 productAttributeDto 中的属性键值对

这里 mybatis 是在寻找 arg0 而不是 productAttributeDto。任何人都可以帮助解决这个问题。我在这里做错了什么?提前致谢。

标签: javamysqlmybatis

解决方案


该错误是由于mapper方法和provider方法的参数名称不匹配造成的。

  • 映射器方法的参数名称由@Param注释指定,​​即productAttributeDto
  • 提供程序方法中未指定参数名称,因此使用默认名称arg0

这些名称必须匹配。


有两种解决方案。

  1. 在提供者方法参数上添加@Param注释。
  2. -parameters在启用编译器选项的情况下构建您的应用程序。

解决方案 1 非常简单。

public static String getProductAttribute(
  @Param("productAttributeDto") final ProductAttributeDto productAttributeDto) {

解决方案 2 取决于您如何构建应用程序。

如果使用 Maven,可能需要在 pom.xml 中配置 maven-compiler-plugin。例如

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <configuration>
        <compilerArgs>
          <arg>-parameters</arg>
        </compilerArgs>
      </configuration>
    </plugin>

使用 IDE 时,您可能需要配置构建设置。

这样,MyBatis 可以从方法签名中检索参数名称,因此您不需要使用@Param注解(@Param不过,如果需要,您仍然可以使用)。

结果,mapper方法可以更简单......

@SelectProvider(type = VariantSqlProvider.class, method = "getProductAttribute")
VariantDto findByProductAttribute(ProductAttributeDto productAttributeDto);

...并且您问题中的提供者方法应该按原样工作。


推荐阅读