본문 바로가기
dev/spring

Spring Data에서 String을 사용하지 않기

by igooo 2026. 10. 15.
728x90

개요

Spring Data를 사용하여 데이터를 처리한 경험이 있다면. 아래 코드들은 익숙한 코드일 것이다.

하지만 DB 스키마가 변경되거나 모델이 변경되는 경우 아래 코드는 컴파일은 문제없이 가능하지만 실제 서비스에 배포해서 실행하게 되면 오류가 발생하는 코드가 된다.

Sort.by("name", "age");

where("user.type").is(...);

기존 Spring Data를 사용하여 쿼리를 코드를 작성할 때 조건식, 정렬 또는 경로 탐색 등 다양한 용도로 도메인 변수를 문자열로 참조하여 작성했다. 하지만 애플리케이션이 시간이 지남에 따라 DB 구조가 변경되는 경우가 많아서 문자열을 사용하여 쿼리를 작성하는 로직에는 분명한 한계가 있었다.

 

개인적으로는 모델 안에 변수명을 상수로 추가하고 상수를 참조하는 방식을 사용했었다.

아래 예제와 같이 작성하면 수정할 위치는 하나로 줄게 되지만 이 또한 name 칼럼이 DB에서 변경되면 문자열을 사용했을 때와 동일하게 컴파일 타임에 오류를 인지하기 된다.

record User(Long id, String name, ...){
    public static final String FIELD_NAME = "name";
    ......
}

 

Metamodel-based 접근 방식

기존에도 문자열을 사용하지 않고, 쿼리를 작성할 수 있는 Querydsl(https://docs.spring.io/spring-data/jpa/reference/repositories/core-extensions.html#core.extensions.querydsl)이나 JPA Metamodel Generator와 같은 프레임워크가 있지만, 별도의 어노테이션 프로세서 또는 전용 빌드 플러그인을 사용해야 사용이 가능했다. 이는 프로젝트의 복잡성을 증가시키고, 러닝 커브 또한 존재하기 때문에 현업에서는 적극적으로 상용되지는 않았다.

 

Type-safe property references

Spring Boot 4.1.1 버전이 출시되면서 Spring Data 버전이 2026.0.1로 올라가게 되었고. 신규 Spring Data에서는 타입 안정성을 보장하여 쿼리를 작성할 수 있는 속성 참조 기능이 추가되었다. (Kotlin을 사용하시는 분들은 기존에도 타입이 안전성을 유지하면 작성이 가능)

 

Spring Boot 4.1.1 이전에는 아래와 같이 코드를 작성했다.

var criteria = Criteria.where("name")
                .in(names)
                .and("age")
                .gt(20);

 

Spring Boot 4.1.1에서는 메서드 참조를 사용하여 type-safe 한 안정한 방법으로 코드를 작성할 수 있게 되었다.

var criteria = Criteria.where(User::name)
                .in(names)
                .and(User::age)
                .gt(20);

 

첫 번째 예제는 문자열 리터럴을 사용하여 코드를 작성했고, 다른 하나는 메서드 참조를 사용하여 코드를 작성했다. 메서드 참조를 사용하면 코드만 봐도 어떤 의도를 가지고 조회하는지 한 번에 알 수 있다.

또한 타입 시스템에 의해 유효성 검사를 받게 된다. 유효하지 않는 경로(클래스가 변경되면) 즉시 오류가 발생하고, IDE를 통해서도 오류가 표시되고, 런타임이 아닌 컴파일 타임에 오류를 인지할 수 있게 된다.

 

또한 기존 문자열 기반 API도 그대로 지원하면서 Type-safe 한 기능도 동시에 지원하기 때문에 문자열을 사용하여 쿼리를 작성하는 코드가 많은 프로젝트라면 Spring Boot 4.1.1로 적용하고 점진적으로 코드를 마이그레이션 할 수도 있다.

신규 프로젝트라면 Spring Boot 4.1.1 기반으로 프로젝트를 생성하고, 아래와 같이 Type-safe 한 코드로 작성하도록 하자.

// Existing code
where("name").is("...")
where("address.county").is("...")
Sort.by("firstName", "lastName");

// Type-safe variants
where(User::name).is("...")
where(PropertyPath.of(User::address).then(Address::county).is("...")
Sort.by(User::firstName, User::lastName)

 

참고

 

 

 

728x90