ysk(0soo)
Lifealong
ysk(0soo)
전체 방문자
오늘
어제
  • 분류 전체보기 (238)
    • Java (50)
      • whiteship-java-study (11)
      • Java (28)
      • time (6)
    • Spring (68)
      • JPA (15)
      • Spring (1)
      • SpringBoot (1)
      • SpringMVC (6)
      • Spring Security (22)
      • Jdbc (1)
      • RestDocs (14)
      • log (6)
    • Kotlin (3)
    • Web (2)
      • nginx (1)
    • Database (14)
      • MySQL (5)
      • PostgreSQL (1)
      • SQL (1)
      • Redis (4)
    • C, C++ (0)
    • Git (1)
    • Docker (2)
    • Cloud (3)
      • AWS (3)
    • 도서, 강의 (0)
      • t5 (0)
    • 기타 (7)
      • 프로그래밍 (1)
    • 끄적끄적 (0)
    • CS (14)
      • 운영체제(OS) (2)
      • 자료구조(Data Structure) (9)
    • 하루한개 (12)
      • 우아한 테크코스-10분테코톡 (12)
    • 스터디 (12)
      • 클린 아키텍처- 로버트마틴 (2)
      • JPA 프로그래밍 스터디 (10)
    • 테스트 (34)
      • JUnit (19)
      • nGrinder (2)
      • JMeter (0)
    • Infra (3)
    • 프로그래머스 백엔드 데브코스 3기 (0)
    • 디자인 패턴 (3)
    • Issue (4)
    • system (1)
      • grafana (0)
      • Prometheus (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록
  • github

공지사항

인기 글

태그

  • LocalDateTime
  • 동등성
  • 트랜잭션
  • querydsl
  • UserDetailsService
  • VirtualThread Springboot
  • DataJpaTest
  • scope value
  • mysql
  • jpa
  • node exporter basic auth
  • 인가(Authorization) 처리
  • 가상 스레드
  • 가상 스레드 예외 핸들링
  • 정규표현식
  • FilterSecurityInterceptor
  • 구조화된 동시성
  • AccessDecisionVoter 커스텀
  • 동일성
  • restdocs custom
  • 동시성 제어
  • junit5
  • nginx basic auth
  • java
  • StructuredConcorrency
  • tree
  • AccessDecisionManager
  • nGrinder
  • restdocs enum
  • AuthenticationException

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
ysk(0soo)

Lifealong

Spring/JPA

Jpa ArrayType. PostgreSQL Array Type을 저장하는 방법 - Hibernate Types, List, Array

2023. 1. 5. 00:34

PostgreSQL을 포함한 몇몇 RDB에서는 Array Type의 컬럼 유형을 지원한다.

그러나 hibernate에서 제공해주는 기본 Type들은 Array Type을 지원하지 않는다.

 

개발자는 Hibernate Type을 Custom 구현해서 사용하거나,

라이브러를 이용해서 PostgreSQL ArrayType을 Spring-data-jpa를 이용해서 hibernate로 매핑할 수 있다.

 

테스트에 사용된 도메인 엔티티는 다음과 같다.

도메인 엔티티

@Entity
public class User {
    @Id
    private Long id;
    private String name;

    private String[] roles;

    private List<String> hobbies;

}

1. Custom Hibernate Type

Hibernate는 다양한 기본 Type을 지정해 주므로 Custom 을 구현하기는 드물지만, 데이터를 저장, 가져오는 것에 대해 Custom Type을 지정할 수 있다.

org.hibernate.type.Type

인터페이스를 구현하거나

org.hibernate.usertype.UserType

인터페이스를 구현하고

타입을 적용할 컬럼에 @Type(type = "패키지명.커스텀타입명") 어노테이션을 적용해서 구현할 수 있다.

 

그 중 UserType을 이용해서 구현한 예제이다.

자바의 String[] 배열을 컬럼의 Array 타입으로 변환하는 Custom Type

public class CustomStringArrayType implements UserType {
    @Override
    public int[] sqlTypes() {
        return new int[]{Types.ARRAY};
    }

    @Override
    public Class returnedClass() {
        return String[].class;
    }

    @Override
    public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner)
      throws HibernateException, SQLException {
        Array array = rs.getArray(names[0]);
        return array != null ? array.getArray() : null;
    }

    @Override
    public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session)
      throws HibernateException, SQLException {
        if (value != null && st != null) {
            Array array = session.connection().createArrayOf("text", (String[])value);
            st.setArray(index, array);
        } else {
            st.setNull(index, sqlTypes()[0]);
        }
    }
    //implement equals, hashCode, and other methods 
}
  • sqlTypes() 메소드 : 매핑된 컬럼에 대한 SQL Type을 반환해야 한다.
    • SQL Type은 java.sql.Types에 정의되어 있다.
  • returnedClass() 메소드 : nullSafeGet() 메소드에 의해 반환될 클래스 타입을 지정해야 한다.
    • SQL Type과 같아야 한다
    • 사용자 지정 커스텀 클래스 (예를들면 Embedded 클래스)도 반환이 가능하다.
  • nullSafeGet() 메소드 : DB에서 값을 읽어온 후 자바 데이터 타입으로 처리한다.
    • null을 반환할 수 있으므로 null 처리가 필요하다.
  • nullSafeSet() 메소드 : DB에 값을 쓸 때, 자바 타입을 어떻게 쓸건지 처리한다.
    • 여기서는 PostgreSQL text 타입의 배열을 지정한다.

 

그런 다음 CustomStringArrayType 클래스를 사용하여 문자열 배열을 PostgreSQL 텍스트 배열에 매핑한다.  

@Entity
public class User {
    //...

    @Column(columnDefinition = "text[]")
    @Type(type = "com.ys.arraymapping.CustomStringArrayType")
    private String[] roles;

}

2. hibernate-types 라이브러리로 매핑

깃허브 : https://github.com/vladmihalcea/hypersistence-utils

vladmihalcea의 오픈소스 라이브러리를 사용하면 쉽게 구현할 수 있다

여기서 다양한 데이터 타입들을 커스텀해서 지원해준다.

  • 라이브러리를 추가하고 필요한것만 사용하면 된다.

의존성 추가

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

하이버네이트 버전에 따른 지원하는 버전이 다르므로, 깃허브 가서 보고 하이브네이트 버전에 맞는 라이브러리 버전을 선택하면 된다.

 

List<String> 타입과 String[] 타입을 매핑하려면 다음과 같이 사용하면 된다.

@TypeDefs({
    @TypeDef(
        name = "string-array",
        typeClass = StringArrayType.class
    ),
    @TypeDef(
    name = "list-array",
    typeClass = ListArrayType.class
        )
})
@Entity
public class User {

  @Id
  private Long id;

  private String name;
  @Type(type = "string-array")
  @Column(
        name = "roles",
        columnDefinition = "text[]"
  )
  private String[] roles;

  @Type(type = "list-array")
  @Column(
        name = "hobbies",
        columnDefinition = "text[]"
   )
  private List<String> hobbies;

}

Custom Type을 구현한것과 같이 CustomStringArrayType 과 유사하게,
String 배열 에 대한 매퍼로서 hibernate-types 라이브러리에서 제공하는 StringArrayType 클래스를 사용할 수 있다.

 

또한, list-array 타입도 지원하므로 List에 대해서도 사용할 수 있다.

  • 라이브러리에서 DateArrayType, EnumArrayType, DoubleArrayType 과 같은 몇 가지 편리한 매퍼도 추가적으로 제공한다.

hibernate-types 에서 지원하는 다양한 Array Types 예제

스키마와 도메인 모델

event라는 Table이 있다. 이 Table의 스키마는 다음과 같다.

 

다음은 event table과 매핑되는 Entity Domain model이다.

 

다음과 같이 매핑할 수 있다.

@Entity(name = "Event")
@Table(name = "event")
@TypeDef(
    name = "list-array",
    typeClass = ListArrayType.class
)
public class Event {

    @Id
    private Long id;

    @Type(type = "list-array")
    @Column(
        name = "sensor_ids",
        columnDefinition = "uuid[]"
    )
    private List<UUID> sensorIds;

    @Type(type = "list-array")
    @Column(
        name = "sensor_names",
        columnDefinition = "text[]"
    )
    private List<String> sensorNames;

    @Type(type = "list-array")
    @Column(
        name = "sensor_values",
        columnDefinition = "integer[]"
    )
    private List<Integer> sensorValues;

    @Type(type = "list-array")
    @Column(
        name = "sensor_long_values",
        columnDefinition = "bigint[]"
    )
    private List<Long> sensorLongValues;

    @Type(
        type = "io.hypersistence.utils.hibernate.type.array.ListArrayType",
        parameters = {
            @Parameter(
                name = ListArrayType.SQL_ARRAY_TYPE,
                value = "sensor_state"
            )
        }
    )
    @Column(
        name = "sensor_states",
        columnDefinition = "sensor_state[]"
    )
    private List<SensorState> sensorStates;

    @Type(type = "list-array")
    @Column(
        name = "date_values",
        columnDefinition = "date[]"
    )
    private List<Date> dateValues;

    @Type(type = "list-array")
    @Column(
        name = "timestamp_values",
        columnDefinition = "timestamp[]"
    )
    private List<Date> timestampValues;

    //Getters and setters omitted for brevity
}

https://vladmihalcea.com/postgresql-array-java-list/

이 사이트에 사용방법이 자주 업데이트 되므로 필요할때마다 가서 보면 된다.

참조

  • https://vladmihalcea.com/postgresql-array-java-list/
  • https://www.baeldung.com/java-hibernate-map-postgresql-array
  • https://github.com/vladmihalcea/hypersistence-utils
저작자표시 비영리 (새창열림)

'Spring > JPA' 카테고리의 다른 글

JPA Hibernate Id 생성 전략과 UUID 전략  (0) 2023.01.18
Jpa Hibernate Custom Id Generator  (1) 2023.01.18
Cannot call sendError() after the response has been committed - 순환 참조 문제 With JPA Entity  (0) 2022.12.23
Jpa 쿼리 파라미터 로그 확인방법 - With DataJpaTest p6spy  (1) 2022.12.17
영속성 전이(Cascade) ManyToOne 시 주의할점 - 상위 엔티티 삭제 문제  (1) 2022.12.15
    'Spring/JPA' 카테고리의 다른 글
    • JPA Hibernate Id 생성 전략과 UUID 전략
    • Jpa Hibernate Custom Id Generator
    • Cannot call sendError() after the response has been committed - 순환 참조 문제 With JPA Entity
    • Jpa 쿼리 파라미터 로그 확인방법 - With DataJpaTest p6spy
    ysk(0soo)
    ysk(0soo)
    백엔드 개발을 좋아합니다. java kotlin spring, infra 에 관심이 많습니다. email : kim206gh@naver.com github : https://github.com/devysk

    티스토리툴바