在Spring Repository中命名查询参数

6
这个例子运行良好。
@Query("select t from TimeTable t where MONTH(t.date) = ?1 and YEAR(t.date) = ?2")
List<TimeTable> findAll(Integer month, Integer year);

现在我尝试使用以下名称替换?1和?2

@Query("select t from TimeTable t where MONTH(t.date) =month and YEAR(t.date) =:year")
List<TimeTable> findAll(Integer month, Integer year);

这个不起作用并且会出现错误:

org.springframework.dao.InvalidDataAccessApiUsageException: 参数在该位置 [1] 不存在;嵌套异常是 java.lang.IllegalArgumentException: 参数在该位置 [1] 不存在

还有这个:

@Query("select t from TimeTable t where MONTH(t.date) =:month and YEAR(t.date) =:year")
List<TimeTable> findAll(Integer month, Integer year);

产生错误:

org.springframework.dao.InvalidDataAccessApiUsageException:参数绑定的名称不能为空!在JDKs < 8上,您需要使用@Param进行命名参数,在JDK 8或更高版本上,请确保使用-parameters进行编译。;嵌套异常是java.lang.IllegalArgumentException:参数绑定的名称不能为空!在JDKs < 8中,您需要使用@Param进行命名参数,在JDK 8或更高版本上,请确保使用-parameters进行编译。

更新:

如上所述的错误消息,我不需要在JDK 8上使用@Param,但使用@Param的解决方案有效:

List<TimeTable> findAll(@Param("month") Integer month, @Param("year") Integer year);

当我删除@Params时,会再次出现这个错误。

YEAR(t.date) =:ear") 拼写错误了吗? - krezus
1
好眼力krezus(我在这里拼错了,代码中一切正常) - degath
3个回答

12

使用@Param命名参数

Spring Data的查询参数是基于它们的位置进行替换的。但是这可能会出现问题,绑定可能容易出错。因此建议在方法参数中使用@Param注解来绑定查询参数名称。在查询中,您需要使用:paramName来指示同一paramName与方法参数绑定。

将您的方法更新如下:

@Query("select t from TimeTable t where MONTH(t.date) =:month and YEAR(t.date) =:year")
List<TimeTable> findAll(@Param("month") Integer month, @Param("year") Integer year);

接口中无法保留方法参数名称

当一个Java类被编译时,默认情况下,Java编译器会更改方法参数名称。例如,如果您编译以下代码:

public class Foo {
  public void bar(int myHolyParam) {}
}

你可能最终会遇到这种情况。
public class Foo {
  public void bar(int arg0) {}
}

您的参数名称已经丢失。您可以通过设置编译器标记,例如 -g:vars 保留名称,但这仅对类有帮助。接口方法参数名称无法保留。在 JDK 8 之前,没有合法的方法来解决这个问题。您可以参考此 SO 问题
在 JDK 8 或更高版本中,请务必使用 -parameters 编译代码。
最近 JDK 8 提供了解决方案。如果要保留方法参数名称(适用于类或接口),您只需告诉编译器设置 -parameter 标记即可。利用 JDK 8 的这个特性,Spring 可以使用反射推断出参数名称。但是请记住,仍然需要使用编译器标记 -parameters 才能具备此功能。
因此,如果您没有使用该标记或正在使用小于 8 的 Java 版本,则必须使用 @Param 注释标记您的参数。
您可以在此处了解有关 Java 8 中命名参数的简要信息:Java 8 中的命名参数

2
第一个异常是因为你写成了=month而不是=:month。这样你只有一个绑定参数但是有两个方法参数,这是不匹配的。
在第二种情况下,您的字节码没有包含有关参数名称的信息。只需按照异常提示执行即可:

参数绑定的名称不能为空! 在JDKs <8上,您需要使用@Param来命名参数,在JDK 8或更高版本中,请确保使用-parameters进行编译。

像这样:
@Query("select t from TimeTable t where MONTH(t.date) =:month and YEAR(t.date) =:year")
List<TimeTable> findAll(@Param("month") Integer month, @Param("year") Integer year);

如果您使用的是Java 8或更高版本,可以采用错误信息中提供的另一种选项:
在 JDK 8 或更高版本上编译时,请确保使用 -parameters 标志。这样做后,您就不需要使用 @Param 注释。
有关背景,请参阅此问题:为什么即使在Java 8上,Spring Data存储库方法参数名称也无法使用?

我在你回答的同时更新了我的答案。 我使用jdk8。这意味着我不需要添加@Param,或者我错了吗? - degath
更新了答案。 - Jens Schauder

0
请尝试对最后一个查询使用这个。
 List<TimeTable> findAll(@Param("month") Integer month, @Param("year") Integer year); 

基于这个错误

你需要使用@Param来命名参数,在JDK 8或更高版本中,请确保使用-parameters进行编译。

请查看此处以获取您的更新问题。


我同时更新了帖子。是的,它可以使用@Param,但我使用JDK 8,所以应该将其删除。 - degath
请查看此处:https://dev59.com/C14c5IYBdhLWcg3wl7bm。你的问题已经在那里得到了回答。 - krezus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接