[SpringBoot/DB] JPA-PostgreSQL text[] 필드 생성하기

다은·2025년 6월 9일
2

SpringBoot

목록 보기
9/12
post-thumbnail

유학생을 위한 한국어 학습 서비스, LearnMate의 개발 일대기입니다.

PostgreSQL은 text[] 등의 배열 형태의 필드 타입을 지원합니다. JPA를 사용해 PostgreSQL의 배열 형태 필드를 사용하는 방법에 대해 알아보겠습니다.


기능 개요는 다음과 같습니다.
1. 사용자가 일기를 작성
2. 외부 API를 이용해 해당 일기의 맞춤법을 분석
3. 분석 결과를 파싱해 entity로 저장
4. SpellingRevision entity에 해당 문법에 대한 예시를 리스트로 저장


1. Hibernate-type

제가 레퍼런스들을 찾아보며 처음 시도했던 타입 변환 방법입니다.

1-1. Hibernate-types Library

hibernate의 기능을 이용해, 변수의 타입을 커스텀할 수 있습니다.

사용하는 hibernate 버전에 따라, 아래 hibernate-type 라이브러리를 추가해 타입을 변경할 수 있습니다. Hibernate 6.xx 버전 이상이라면 types-60을, 5.xx 버전이라면 types-52를 사용해야 합니다.

implementation("com.vladmihalcea:hibernate-types-60:2.21.1")

external library 리스트를 확인했을 때, 저는 Hibernate-core 6.xx 버전을 사용하므로, -60 버전의 라이브러리를 추가했습니다.


1-2. @TypeDef, @Type

구현하려는 entity는 다음과 같습니다.

@Entity
@Table(name = "spelling_revision")
data class SpellingRevision(

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    var spellingRevisionId: Long = 0,

    @Column(nullable = false, length = 100)
    var originContent: String,

    @Column(nullable = false, length = 100)
    var revisedContent: String,

	// List<String> type의 필드로 커스텀
    @Column(nullable = true, columnDefinition = "text[]")
    var examples: List<String>? = null,

    ...

위에서 추가한 hibernate-type, core 을 이용해 쉽게 필드를 커스텀할 수 있습니다.

@TypeDef, @Type 어노테이션을 이용해 필드의 타입을 명시적으로 지정해주면 됩니다. List<String> 타입을 사용할 것이므로, 타입의 클래스를 StringArrayType으로 명시해주었습니다.

@Entity
@Table(name = "spelling_revision")
@TypeDef(
    name = "string-array",
    typeClass = StringArrayType::class
)
data class SpellingRevision(
	...
 @Type(type = "string-array")
 @Column(nullable = true, columnDefinition = "text[]")
 var examples: List<String>? = null,

여러 레퍼런스들을 찾아보며, 위의 어노테이션들을 이용해 코드를 작성했으나, @TypeDef 어노테이션이 import되지 않았습니다. hiberante-type 라이브러리 자체에 없더군요.

알고보니 Hibernate.6.x 이상의 버전에서는 @TypeDef가 사라졌다고 합니다. 따라서, 해당 어노테이션은 제거하고 @Type 어노테이션만 붙인 상태에서 애플리케이션을 실행해보았습니다.

또한, hibernate는 보통 List보다 Array를 더 많이 사용한다고 하기에, List를 Array로 수정했습니다.

@Type(value = StringArrayType::class)
@Column(nullable = true, columnDefinition = "text[]")
var examples: Array<String>? = null

이 상태에서 애플리케이션을 실행하면, ClassCast 오류가 발생합니다.

java.lang.ClassCastException: org.hibernate.type.CustomType cannot be cast to org.hibernate.type.BasicPluralType

해당 오류는 hibernate가 내부적으로 필드의 타입을 캐스팅 할 때 오류가 나는 것입니다. @Type 대신 Hibernate6에서 호환 가능한 다른 어노테이션을 사용해보았습니다.


2. JdbcTypeCode

2-1. @JdbcTypeCode

위에서 추가한 dependency는 충돌을 피하기 위해 제거하고, @JdbcTypeCode 어노테이션을 이용해 필드 타입을 명시해주었습니다.

@JdbcTypeCode(SqlTypes.ARRAY)
@Column(nullable = true, columnDefinition = "text[]")
var examples: Array<String>? = null

2-2. Test

아래 코드대로, examples 필드를 Array type으로 캐스팅해 entity를 저장해줍니다.

// save separate spelling analysis
        val revisions = spellingAnalysisResponse.revisedSentences
            ?.flatMap { it.revisedBlocks.orEmpty() }
            ?.flatMap { block ->
                block.revisions.map { revision ->
                    SpellingRevision(
                        originContent = block.origin.content,
                        beginOffset = block.origin.beginOffset,
                        revisedContent = revision.revised,
                        // Array<String> type field
                        examples = revision.examples.toTypedArray(),
                        comment = revision.comment,
                        spelling = spelling
                    )
                }
            }.orEmpty()
        spellingRevisionRepository.saveAll(revisions)

위의 어노테이션을 이용하니, 성공적으로 DB에 text[] 타입의 필드가 생성되었습니다.



필드 타입 캐스팅하는 두 가지 방법에 대해 살펴보았습니다.
사용하는 Hibernate 버전에 따라서, 1, 2번 중 알맞은 방법을 사용하는 것을 추천드립니다.

profile
CS 마스터를 향해 ..

0개의 댓글