문제 해결 과정 (Problem Solving Journey)/버그 픽스 스토리

Spring Data JPA에서 @Param 어노테이션으로 매개변수 바인딩 문제 해결하기

코린이ch 2024. 10. 13. 13:28

Spring Data JPA를 사용하여 개발을 진행하다 보면 때때로 예상치 못한 문제에 부딪힐 수 있습니다. 최근  겪은 문제 중 하나는 JPA 리포지토리 메서드에서 매개변수 바인딩과 관련된 것이었습니다. 이 글에서는 그 문제의 발생 원인과 해결 과정, 그리고 @Param 어노테이션의 중요성에 대해 설명하고자 합니다.

문제 상황

다음과 같은 JPA 리포지토리 메서드를 가지고 있었습니다:

@Query("SELECT MAX(er.score) FROM ExerciseRecord er WHERE er.member.id = :memberId AND er.exercise.id = :exerciseId")
Integer getPersonalBestScore(Long memberId, Long exerciseId);

이 메서드를 호출할 때, 다음과 같은 오류 메시지가 발생했습니다:

For queries with named parameters you need to provide names for method parameters; Use @Param for query method parameters, or when on Java 8+ use the javac flag -parameters

문제의 원인

이 오류는 Spring Data JPA가 메서드 매개변수의 이름을 인식하지 못해 발생합니다. 기본적으로 Java 컴파일러는 컴파일된 클래스 파일에 매개변수 이름 정보를 포함하지 않습니다. 따라서 런타임에 Spring Data JPA는 어떤 매개변수가 어떤 쿼리 파라미터에 매핑되어야 하는지 알 수 없게 됩니다.

@Param 어노테이션 소개

@Param 어노테이션은 Spring Data JPA에서 제공하는 기능으로, 메서드 매개변수와 쿼리의 명명된 파라미터를 명시적으로 연결합니다. 이 어노테이션을 사용하면 컴파일러 설정과 관계없이 매개변수 바인딩을 올바르게 처리할 수 있습니다.

해결 과정

문제를 해결하기 위해 다음과 같이 @Param 어노테이션을 추가했습니다:

@Query("SELECT MAX(er.score) FROM ExerciseRecord er WHERE er.member.id = :memberId AND er.exercise.id = :exerciseId")
Integer getPersonalBestScore(@Param("memberId") Long memberId, @Param("exerciseId") Long exerciseId);

이렇게 수정함으로써, Spring Data JPA는 각 매개변수가 어떤 쿼리 파라미터에 매핑되어야 하는지 정확히 알 수 있게 되었습니다.

추가적인 해결 방법

@Param 어노테이션 사용 외에도, Java 8 이상을 사용한다면 컴파일러 플래그를 통해 이 문제를 해결할 수 있습니다. Gradle을 사용하는 경우, build.gradle 파일에 다음과 같은 설정을 추가할 수 있습니다:

tasks.withType(JavaCompile) {
    options.compilerArgs += ['-parameters']
}

이 설정은 컴파일된 클래스 파일에 매개변수 이름 정보를 포함시킵니다. 하지만 이 방법은 모든 개발 환경에서 일관되게 적용되어야 하므로, 팀 프로젝트에서는 @Param 어노테이션을 사용하는 것이 더 안전할 수 있습니다.

결론

@Param 어노테이션은 Spring Data JPA에서 매개변수 바인딩 문제를 해결하는 간단하면서도 효과적인 방법입니다. 이 어노테이션을 사용함으로써, 코드의 명확성을 높이고 런타임 오류를 방지할 수 있습니다. 또한, 컴파일러 설정에 관계없이 일관된 동작을 보장할 수 있어 팀 프로젝트에서 특히 유용합니다.