1. 개요

PostgreSQL 은 테이블의 열 유형으로 정의될 모든 유형(내장 또는 사용자 정의)의 배열을 지원합니다 . 이 예제에서 우리는 PostgreSQL 배열을 Hibernate 와 매핑하는 몇 가지 방법을 탐구할 것 입니다.

2. 기본 설정

PostgreSQL 데이터베이스와 연결하기 위한 전제 조건으로 Hibernate 구성과 함께 최신 postgresql Maven 의존성을 pom.xml 에 추가해야 합니다. 또한 String 배열 역할 을 사용하여 User 라는 엔터티 클래스를 생성해 보겠습니다 .

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

    private String[] roles;

    //getters and setters 
}

3. 커스텀 하이버네이트 타입

Hibernate는 사용자 정의 유형을 SQL 쿼리에 매핑하는 사용자 정의 유형을 지원합니다. 따라서 데이터를 저장/패치하기 위해 Hibernate와 PostgreSQL 어레이를 매핑하는 사용자 정의 유형을 생성할 수 있습니다 . 먼저, String 배열 을 매핑하기 위한 커스텀 타입을 제공하기 위해 Hibernate의 UserType 클래스 를 구현하는 CustomStringArrayType 클래스 를 생성하자 :

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 
}

여기에서 우리는 반환된 클래스 메서드 의 반환 유형이 String 배열 이라는 점에 주목해야 합니다 . 또한 nullSafeSet 메서드 는 PostgreSQL 유형 text 의 배열을 만듭니다 .

4. 커스텀 하이버네이트 타입으로 배열 매핑하기

4.1. 사용자 엔터티

그런 다음 CustomStringArrayType 클래스를 사용하여 String 배열 역할 을 PostgreSQL 텍스트 배열 에 매핑합니다 .

@Entity
public class User {
    //...

    @Column(columnDefinition = "text[]")
    @Type(type = "com.baeldung.hibernate.arraymapping.CustomStringArrayType")
    private String[] roles;
  
   //getters and setters 
}

그게 다야! 사용자  엔터티 에서 CRUD 작업을 수행하기 위한 사용자 지정 유형 구현 및 배열 매핑이 준비되었습니다  .

4.2. 단위 테스트

사용자 정의 유형을 테스트하기 위해 먼저 String 배열 역할 과 함께 User 객체를 삽입하겠습니다 .

@Test
public void givenArrayMapping_whenArraysAreInserted_thenPersistInDB() 
  throws HibernateException, IOException {
    transaction = session.beginTransaction();

    User user = new User();
    user.setId(2L);
    user.setName("smith");

    String[] roles = {"admin", "employee"};
    user.setRoles(roles);

    session.persist(user);
    session.flush();
    session.clear();

    transaction.commit();

    User userDBObj = session.find(User.class, 2L);

    assertEquals("smith", userDBObj.getName());
}

또한 PostgreSQL 텍스트 배열 형식의 역할 을 포함하는 사용자 레코드를 가져올 수 있습니다 .

@Test
public void givenArrayMapping_whenQueried_thenReturnArraysFromDB() 
  throws HibernateException, IOException {
    User user = session.find(User.class, 2L);

    assertEquals("smith", user.getName());
    assertEquals("admin", user.getRoles()[0]);
    assertEquals("employee", user.getRoles()[1]);
}

4.3. 사용자 정의 정수 배열 유형

마찬가지로 PostgreSQL에서 지원하는 다양한 배열 유형에 대한 사용자 정의 유형을 생성할 수 있습니다. 예를 들어 PostgreSQL int 배열 을 매핑하기 위해 CustomIntegerArrayType 을 생성해 보겠습니다.

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

    @Override
    public Class returnedClass() {
        return Integer[].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("int", (Integer[])value);
            st.setArray(index, array);
        } else {
            st.setNull(index, sqlTypes()[0]);
        }
    }

    //implement equals, hashCode, and other methods 
}

CustomStringArrayType 클래스 에서 발견한 것과 유사하게 , 반환된Class 메서드 의 반환 유형은 Integer 배열 입니다. 또한 nullSafeSet 메소드 의 구현은 PostgreSQL 유형 int 의 배열을 생성합니다 . 마지막으로 CustomIntegerArrayType 클래스를 사용하여 정수 배열 위치 를 PostgreSQL int 배열에 매핑할 수 있습니다.

@Entity
public class User {
    //...
    
    @Column(columnDefinition = "int[]")
    @Type(type = "com.baeldung.hibernate.arraymapping.CustomIntegerArrayType")
    private Integer[] locations;

    //getters and setters
}

5. 최대 절전 모드 유형으로 배열 매핑

반면에 String , Integer , Long 과 같은 각 유형에 대해 사용자 정의 유형을 구현하는 대신 유명한 Hibernate 전문가 Vlad Mihalcea가 개발한 hibernate 유형 라이브러리 를 사용할 수 있습니다 .

5.1. 설정

먼저 pom.xml 에 최신 hibernate-types-52 Maven 의존성을 추가합니다 .

<dependency>
    <groupId>com.vladmihalcea</groupId>
    <artifactId>hibernate-types-52</artifactId>
    <version>2.10.4</version>
</dependency>

5.2. 사용자 엔터티

다음으로 User 엔터티에 통합 코드를 추가하여 String 배열 phoneNumbers 를 매핑합니다 .

@TypeDefs({
    @TypeDef(
        name = "string-array",
        typeClass = StringArrayType.class
    )
})
@Entity
public class User {
    //...
    @Type(type = "string-array")
    @Column(
        name = "phone_numbers",
        columnDefinition = "text[]"
    )
    private String[] phoneNumbers;

    //getters and setters
}

여기에서 커스텀 타입 CustomStringArrayType 과 유사하게 , 우리는 Hibernate-types 라이브러리에 의해 제공되는 StringArrayType 클래스를 String 배열 을 위한 매퍼로 사용했습니다 . 마찬가지로 라이브러리에서 DateArrayType , EnumArrayTypeDoubleArrayType 과 같은 몇 가지 편리한 매퍼 를 찾을 수 있습니다 .

5.3. 단위 테스트

그게 다야! hibernate-types 라이브러리 를 사용하여 배열 매핑을 할 준비가 되었습니다 . 삽입 작업을 확인하기 위해 이미 논의된 단위 테스트를 업데이트해 보겠습니다.

@Test
public void givenArrayMapping_whenArraysAreInserted_thenPersistInDB() 
  throws HibernateException, IOException {
    transaction = session.beginTransaction();
    
    User user = new User();
    user.setId(2L);
    user.setName("smith");
    
    String[] roles = {"admin", "employee"};
    user.setRoles(roles);
    
    String[] phoneNumbers = {"7000000000", "8000000000"};
    user.setPhoneNumbers(phoneNumbers);
    
    session.persist(user);
    session.flush();
    session.clear();
    
    transaction.commit();
}

마찬가지로 읽기 작업을 확인할 수 있습니다.

@Test
public void givenArrayMapping_whenQueried_thenReturnArraysFromDB() 
  throws HibernateException, IOException {
    User user = session.find(User.class, 2L);

    assertEquals("smith", user.getName());
    assertEquals("admin", user.getRoles()[0]);
    assertEquals("employee", user.getRoles()[1]);
    assertEquals("7000000000", user.getPhoneNumbers()[0]);
    assertEquals("8000000000", user.getPhoneNumbers()[1]);
}

6. 결론

이 기사에서 우리는 PostgreSQL 어레이를 Hibernate와 매핑하는 방법을 탐구했습니다. 먼저 Hibernate의 UserType 클래스 를 사용하여 String 배열을 매핑하는 사용자 정의 유형을 생성했습니다. 그런 다음 사용자 지정 유형을 사용하여 PostgreSQL 텍스트 배열을 Hibernate와 매핑했습니다. 마지막으로 PostgreSQL 배열을 매핑하기 위해 hibernate-types 라이브러리를 사용했습니다. 평소와 같이 소스 코드는  GitHub에서 사용할 수 있습니다 .

Persistence footer banner