
FastAPI에서 Spring으로 마이그레이션하던 중 다음과 같은 에러가 발생했다:
2024-12-31 10:08:03 WARN [http-nio-127.0.0.1-8000-exec-2] o.h.e.jdbc.spi.SqlExceptionHelper - SQL Error: 0, SQLState: 42804
2024-12-31 10:08:03 ERROR [http-nio-127.0.0.1-8000-exec-2] o.h.e.jdbc.spi.SqlExceptionHelper - ERROR: column "search_vector" is of type tsvector but expression is of type character varying
Hint: You will need to rewrite or cast the expression.
이 에러는 PostgreSQL의 tsvector 타입 컬럼(search_vector)에 character varying 타입 데이터를 직접 삽입하려 했기 때문에 발생했다.
기존 FastAPI 애플리케이션에서는 이러한 문제가 없었으나, Spring으로 마이그레이션하면서 이슈가 드러났다.
PostgreSQL의 search_vector 컬럼은 전문 검색(Full Text Search)을 지원하기 위해 tsvector 타입으로 설정되어 있다.
Spring JPA는 엔티티 매핑 시 이를 일반 문자열(character varying)로 처리하려고 시도하였고, 타입 불일치로 인해 SQL 오류가 발생했다.
처음에는 애플리케이션 계층에서 search_vector 값을 적절히 변환하거나 삽입을 방지하려는 접근을 고려했다.
하지만 다음과 같은 이유로 더 적합한 방식은 아니라고 판단했다:
PostgreSQL 트리거를 사용하여 search_vector 값을 자동으로 업데이트하도록 설정했다.
이를 통해 애플리케이션 계층에서는 search_vector 컬럼을 업데이트하지 않고도 데이터베이스가 알아서 처리하도록 만들었다.
CREATE FUNCTION users_search_vector_trigger() RETURNS trigger AS $$
BEGIN
NEW.search_vector := to_tsvector('english',
COALESCE(NEW.username, '') || ' ' ||
COALESCE(NEW.email, '')
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER users_search_vector_update
BEFORE INSERT OR UPDATE ON users
FOR EACH ROW
EXECUTE FUNCTION users_search_vector_trigger();
이 트리거는 users 테이블에 데이터가 삽입되거나 업데이트될 때마다 search_vector 컬럼을 자동으로 갱신한다.
Spring JPA에서 search_vector 컬럼이 애플리케이션에서 수정되지 않도록 아래와 같이 설정한다:
@Column(name = "search_vector", columnDefinition = "tsvector", updatable = false)
private String searchVector;
@Transactional
public UserResponse updateUser(int userId, UserUpdate request) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new CommonException(ErrorCode.USER_NOT_FOUND));
if (request.getPassword() != null) {
request = UserUpdate.builder()
...
...
}
user.update(request);
return userMapper.mapToDTO(user);
}
이제 search_vector 필드는 애플리케이션 코드에서 업데이트되지 않으며, 데이터베이스에서 트리거로 자동 처리된다.
이번 문제 해결 과정에서 중요한 것은 올바른 접근 방식을 선택하는 것이었다. 처음에는 Spring 애플리케이션에서 모든 것을 해결하려 했지만, 과감하게 데이터베이스 레벨의 해결책으로 방향을 전환했다.
PostgreSQL 트리거를 활용한 해결책은 단순히 문제를 해결하는 것을 넘어, 시스템 전체의 품질을 향상시켰다. 코드는 더 간결해졌고, 성능은 개선되었으며, 유지보수도 더 쉬워졌다.
이 경험은 문제를 한 걸음 뒤로 물러서서 바라보고, 빠르게 실행하며 개선하는 과정의 중요성을 다시 한 번 상기시켜 주었다. 현재 정식 출시 전이지만, 이러한 접근은 더 나은 시스템을 만들고 사용자에게 더 나은 서비스를 제공하는 기반이 될 것이다.