Spring Data JPA Repository 에서 Stored 프로시저 호출
1. Overview
저장 프로시저(Stored Procedure)는 데이터베이스에 미리 정의된 SQL 문들의 집합이다. 자바에서는 저장 프로시저에 접근하는 여러 방법이 있다. 이 아티클에서는 Spring Data JPA Repository를 통해 저장 프로시저를 호출하는 방법에 대해 학습한다.
2. Project Setup
먼저, 데이터 접근 계층으로 Spring Boot Starter Data JPA 모듈을 사용할 것이다. 또한, 데이터베이스로는 MySQL을 사용한다.
프로젝트 설정을 위해 필요한 Gradle 의존성은 다음과 같다.
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
runtimeOnly 'com.mysql:mysql-connector-j'
}
3. Entity Class
Spring Data JPA에서 엔티티(Entity)는 데이터베이스에 저장된 테이블을 나타낸다. 우리는 Car라는 간단한 엔티티를 사용할 것이다.
@Entity
public class Car {
@Id
private int id;
private String model;
private int year;
// 표준 생성자, getter, setter
}
4. Stored Procedure Creation
다음으로, MySQL 데이터베이스에 저장 프로시저를 생성해야 한다. 이 아티클에서는 두 종류의 프로시저를 생성한다: 하나는 입력 파라미터만 있고, 다른 하나는 출력 파라미터도 있다.
4.1. Stored Procedure With an IN Parameter
파라미터를 통해 입력값을 받아 그에 따라 다른 결과를 얻을 수 있다. 예를 들어, 특정 연도 이후의 자동차 목록을 반환하는 저장 프로시저는 다음과 같이 작성할 수 있다.
CREATE PROCEDURE FIND_CARS_AFTER_YEAR(IN year_in INT)
BEGIN
SELECT * FROM car WHERE year >= year_in ORDER BY year;
END
이 프로시저는 year_in이라는 정수형 입력 파라미터를 받는다.
4.2. Stored Procedure With an OUT Parameter
저장 프로시저는 OUT 파라미터를 사용하여 호출 애플리케이션에 데이터를 반환할 수도 있다. 예를 들어, 특정 모델의 자동차 수를 계산하는 프로시저는 다음과 같다.
CREATE PROCEDURE GET_TOTAL_CARS_BY_MODEL(IN model_in VARCHAR(255), OUT count_out INT)
BEGIN
SELECT COUNT(*) INTO count_out FROM car WHERE model = model_in;
END
여기서 model_in은 입력 파라미터이고, count_out은 질의 결과를 저장하는 출력 파라미터이다.
5. Reference Stored Procedures in Repository
Spring Data JPA에서 Repository는 데이터베이스 연산을 제공하는 곳이다. Car 엔티티에 대한 데이터베이스 연산을 위해 Repository를 구성하고, 여기에 저장 프로시저를 참조할 수 있다.
@Repository
public interface CarRepository extends JpaRepository<Car, Integer> {
// 저장 프로시저 호출 메서드들이 여기에 정의된다.
}
이제 이 Repository 인터페이스에 여러 가지 방법으로 저장 프로시저를 호출하는 메서드를 추가할 것이다.
5.1. Using the @NamedStoredProcedureQuery Annotation
JPA는 @NamedStoredProcedureQuery 애너테이션을 통해 엔티티에 저장 프로시저를 바인딩하는 표준적인 방법을 제공한다.
먼저 Car 엔티티를 수정하여 명명된 저장 프로시저 쿼리를 정의한다.
@Entity
@NamedStoredProcedureQuery(
name = "findCarsAfterYear",
procedureName = "FIND_CARS_AFTER_YEAR",
parameters = {
@StoredProcedureParameter(mode = ParameterMode.IN, name = "year_in", type = Integer.class)
}
)
public class Car {
// ... 기존 코드
}
그 다음, Repository에 이 명명된 프로시저를 참조하는 메서드를 추가한다.
@Procedure(name = "findCarsAfterYear")
List<Car> findCarsAfterYear(@Param("year_in") Integer year_in);
@Procedure 애너테이션의 name 속성은 @NamedStoredProcedureQuery에 정의된 name을 가리킨다. @Param 애너테이션은 메서드 파라미터를 저장 프로시저 파라미터에 매핑하는 데 사용된다.
5.2. Using the @Procedure Annotation
@Procedure 애너테이션을 사용하여 저장 프로시저 메서드를 직접 정의하고, 프로시저 이름을 매핑할 수도 있다. 이를 위한 네 가지 동등한 방법이 존재한다.
예를 들어, 저장 프로시저 이름을 메서드 이름으로 직접 사용할 수 있다.
@Procedure
int GET_TOTAL_CARS_BY_MODEL(String model);
Spring Data는 밑줄(_)을 카멜케이스(camel-case)로 변환하여 메서드 이름으로부터 저장 프로시저 이름을 유추한다. 따라서 getTotalCarsByModel이라는 메서드 이름은 GET_TOTAL_CARS_BY_MODEL 프로시저와 자동으로 매핑된다.
@Procedure
int getTotalCarsByModel(String model);
만약 다른 메서드 이름을 사용하고 싶다면, @Procedure 애너테이션의 요소로 저장 프로시저 이름을 명시하면 된다.
@Procedure("GET_TOTAL_CARS_BY_MODEL")
int getTotalCarsByModel(String model);
혹은 procedureName 속성을 사용할 수도 있다.
@Procedure(procedureName = "GET_TOTAL_CARS_BY_MODEL")
int getTotalCarsByModel(String model);
이 모든 경우에, Spring Data는 메서드 시그니처를 분석하여 파라미터들을 자동으로 매핑한다.
5.3. Using the @Query Annotation
@Query 애너테이션을 사용하여 저장 프로시저를 직접 호출할 수도 있다.
@Query(value = "CALL FIND_CARS_AFTER_YEAR(:year_in);", nativeQuery = true)
List<Car> findCarsAfterYear(@Param("year_in") Integer year_in);
이 메서드에서는 네이티브 쿼리를 사용하여 저장 프로시저를 호출한다. 쿼리는 애너테이션의 value 속성에 저장된다. 마찬가지로 @Param을 사용하여 저장 프로시저의 입력 파라미터를 매칭하고, 프로시저의 출력은 Car 엔티티 객체 리스트에 매핑한다.
아래 표는 위에서 설명한 세 가지 접근 방식의 특징을 요약한 것이다.
접근 방식 | 장점 | 단점 | 사용 사례 |
@NamedStoredProcedureQuery | JPA 표준, 재사용 가능, 중앙 관리 | 엔티티 클래스 수정 필요, 설정이 다소 복잡 | 여러 Repository에서 공통 프로시저를 사용할 때 |
@Procedure | 간결하고 직관적, Repository 내 정의 | Spring Data JPA에 특화됨 | 특정 Repository에서만 프로시저를 사용할 때 |
@Query | 유연함, 간단한 호출에 적합 | 프로시저 호출 구문을 직접 작성해야 함 | 간단한 CALL 구문으로 충분할 때 |
6. Summary
이 아티클에서는 Spring Data JPA Repository를 통해 데이터베이스 저장 프로시저를 호출하는 다양한 방법을 살펴보았다.
@NamedStoredProcedureQuery, @Procedure, @Query 애너테이션을 사용하는 방법을 각각 다루었다. 각 방법은 고유의 장점을 가지며, 특정 요구사항과 선호도에 따라 선택할 수 있다.
원본: https://www.baeldung.com/spring-data-jpa-stored-procedures