본문 바로가기

스프링 독학 여정

JPA 배열 column 만들기

😱 요구사항

  • 상품 테이블에 옷 사이즈열이 있다. 사이즈 여러 개를 데이터로 넣고 싶은데 어떻게 해야할까?
  • 배열을 값으로 넣을 수는 없을까?
  • 그래서 column 타입을 배열로 하니까 오류가 난다ㅠㅠ
// 오류나는 코드
@Column
private String[] clothSize; //옷 사이즈

사용 DB: PostgreSQL

 

🚩 해결방법

  • 배열 커스텀 타입 클래스를 생성해야 한다

 

Item entity

import lombok.*;
import mirim.itshow.kiru.entity.enum_col.Size;
import org.hibernate.annotations.Type;

import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.*;

@Data //TODO 엔티티에 @Data쓰면 set 남용 때문에 안 좋음
@Entity //엔티티
@Table(name = "item")
public class Item {

    @Id
    @Column
    private Long itemId; //상품 고유 id
    
    @Column(columnDefinition = "text[]")
    @Type(type = "mirim.itshow.kiru.entity.hibernatesetting.CustomStringArrayType")
    private String[] clothSize; //옷 사이즈

	// 생성자, 일부 column 생략
}

 

text[ ]는 뭐고, @Type 어노테이션은 왜 있는 걸까? 차근차근 보도록 하자

 

 

CustomStringArrayType.java

커스텀한 배열 타입 클래스가 필요하다

나는 entity 폴더 안에 hibernatesetting 폴더를 만들어서 클래스를 만들어줬다

✨ 아래 코드를 복붙하여서 새로운 클래스를 생성하자! ✨ 

코드가 길어보이는 이유는 추상메서드 구현 때문이다

import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.usertype.UserType;

import java.io.Serializable;
import java.sql.*;

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

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

    @Override
    public boolean equals(Object x, Object y) throws HibernateException {
        return false;
    }

    @Override
    public int hashCode(Object x) throws HibernateException {
        return 0;
    }

    @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]);
        }
    }

    @Override
    public Object deepCopy(Object value) throws HibernateException {
        return null;
    }

    @Override
    public boolean isMutable() {
        return false;
    }

    @Override
    public Serializable disassemble(Object value) throws HibernateException {
        return null;
    }

    @Override
    public Object assemble(Serializable cached, Object owner) throws HibernateException {
        return null;
    }

    @Override
    public Object replace(Object original, Object target, Object owner) throws HibernateException {
        return null;
    }
    //implement equals, hashCode, and other methods
}

자기 입맛대로 nullSafeSet() 메서드 안에 있는 데이터 타입이나 배열명을 수정하면 된다


여기서 다시 위로 올라가 Entity를 살펴보자

    @Column(columnDefinition = "text[]")
    @Type(type = "mirim.itshow.kiru.entity.hibernatesetting.CustomStringArrayType")
    private String[] clothSize; //옷 사이즈
  • 커스텀 클래스의 nullSafeSet() 메서드에서 설정했던 이름대로
  • columnDefinition 속성을 text[]로 설정하고
  • 커스텀 배열 클래스를 type으로 설정해준다

 

값 넣어주기

item1.setClothSize(new String[]{"S", "M", "L"});

set 메서드 안에 배열을 만들어서 넣어주면 된다

 

 

🙇‍♂️ 더 쉬운 방법이 있다면 댓글에 남겨주세요 🙇‍♂️

참고: https://www.baeldung.com/java-hibernate-map-postgresql-array

'스프링 독학 여정' 카테고리의 다른 글

HTTP header, body란?  (0) 2023.05.31
JPA fk column으로 findBy하기  (0) 2023.05.18
스프링 입문 독학 :: day1 - 1.프로젝트 생성  (0) 2023.01.03