[JPA]필드와 컬럼 매핑

Inung_92·2023년 10월 26일
1

JPA

목록 보기
6/7
post-thumbnail

해당 포스팅의 내용은 김영한 강사님의 자바 ORM 표준 JPA 프로그래밍 책의 내용을 정리하여 작성하였습니다.


필드와 컬럼 매핑

엔티티의 필드와 컬럼을 매핑하기 위해 JPA에서 제공하는 다양한 어노테이션에 대해서 알아보자. 해당 내용은 어떻게 사용하는지에 중점을 두고 작성하도록 하겠다.

분류

자세한 내용을 시작하기 전에 간단하게 어떤 어노테이션이 있는지 알아보자

  • @Column : 컬럼을 매핑
  • @Enumerated : Enum 타입을 매핑
  • @Temporal : 날짜 타입을 매핑
  • @Lob : BLOB, CLOB 등의 길이 제한이 없는 문자열 타입을 매핑
  • @Transient : 해당 필드를 매핑하지 않음을 지정
  • @Access : JPA가 엔티티에 접근하는 방식 설정

위에서 나열한 매핑 어노테이션 이외에도 많이 있지만 기타 어노테이션들은 계속 JPA 공부를 이어나가면서 알아보도록 하겠다.

@Column

📖엔티티의 필드를 테이블의 컬럼과 매핑한다.

가장 많이 사용되면서 기능이 많은 어노테이션이다. 속성은 어떤 것들있는지 알아보자.

속성

속성명기능기본값
name필드와 매핑할 컬럼명필드명
insertable(중요도 낮음)엔티티 저장 시 해당 필드를 저장할지 말지에 대한 설정true
updatable(중요도 낮음)엔티티 수정 시 해당 필드를 수정할지 말지에 대한 설정true
table(중요도 낮음)하나의 엔티티에 2개 이상의 테이블을 매핑할 때 사용하며 해당 어노테이션으로 지정한 필드는 다른 테이블에 매핑가능현재 엔티티의 매핑된 테이블
nullable(DDL)null 값의 허용 여부를 설정true
unique(DDL)유니크 제약조건 여부를 설정-
length(DDL)String 타입에만 사용가능한 길이 제약조건255
precision, scale(DDL)BigDecimal 또는 BigInteger 타입에서 사용하며 precision은 수소점을 포함한 전체자릿수, scale은 소수의 자릿수이다.precision = 19(합쳐서 19개의 숫자)
scale = 2(소수점 2번째까지)
columnDefinition컬럼 생성 시 세부적인 조건(자료형, 길이, 기본값 등)을 설정-

위 표를 보면 DDL에 해당하는 속성이 많이 있는 것을 볼 수 있다. DDL 속성에 따라 실제 SQL문은 어떻게 생성되는지 보자.

// nullable
@Column(nullable = false)
private String data;

SQL : data varchar(255) not null

// unique
@Column(unique = true)
private String userName;

SQL : alter table tablename add constraint UK_xxx unique (username)

// columnDefinition
@Column(columnDefinition = "varchar(100) default 'test'")
private String data;

SQL : data varchar(100) default 'test'

// length
@Column(length = 200)
private String data;

SQL : data varchar(100)

주의 사항

만약 @Column을 생략하면 어떤 상황이 벌어지는지 알아보자.

@Column 어노테이션은 필드가 자바의 기본 타입일 때 nullable속성 예외가 있다. 아래 코드를 통해 알아보자.

// 1
int data1; // 어노테이션 생략, 기본 타입
data1 integer not null // 생성된 SQL

// 2
Integer data2; // 어노테이션 생략, 객체 타입
data2 integer // 생성된 SQL

// 3
@Column
int data3; // 어노테이션 명시, 기본 타입
data integer // 생성된 SQL

위 코드를 보면 1번에서 기본 타입으로 생성한 필드에 대한 SQL은 not null 제약 조건을 자동으로 추가한다. 이러한 이유는 기본 타입 필드에 null값이 들어갈 수 없기 때문이다. 2번은 래퍼 클래스로 객체 타입을 필드로 선언하였는데 이 때는 not null 제약 조건이 추가되지 않는다. 객체 타입은 null 값이 허용 가능하기 때문이다.

3번을 보면 어노테이션을 명시하고 기본 타입을 선언하였더니 not null 제약조건을 추가하지 않았다. 이유는 @Column 어노테이션의 nullable 속성의 기본 값이 true이기 때문에 설정하지 않는 것이다.

위와 같은 이유로 자바 기본 타입에 @Column 어노테이션을 사용한다면 nullable = false로 지정하는 것이 안전하다.

@Enumerated

📖자바의 enum 타입을 매핑한다.

속성

속성명기능기본값
EnumType.ORDINALenum의 순서대로 데이터베이스에 저장기본값
EnumType.STRINGenum 이름을 문자열로 데이터베이스에 저장-

사용하는 방법은 다음과 같다.

// Enum 선언
public enum RoleType{
	ADMIN, USER
}

// 이름으로 매핑
@Enumerated(EnumType.STRING)
private RoleType roleType;

// 순서로 매핑
@Enumerated(EnumType.ORDINAL)
private RoleType roleType;

두 가지 방법에 대한 차이를 알아보자.

  • ORDINAL : enum에 선언된 순서를 데이터베이스에 반영한다. 예를 들면 ADMIN은 0, USER는 1이 되는 것이다.
  • STRING : enum의 이름을 데이터베이스에 저장한다.

두 방법의 차이는 ORDINAL의 경우 순서가 바뀔 경우 반영이 제한적이며 수정할 코드가 많아지는 반면 데이터의 저장되는 크기가 작다. 반대로 STRING은 데이터의 크기는 크지만 순서가 바뀌어도 수정 소요가 많지 않으며 안전하다. 가급적이면 STRING을 사용하는 것이 안전하다.

@Temporal

📖날짜 타입에 대한 매핑을 한다.

속성

속성명기능기본값
value-TemporalType.DATE : 날짜를 데이터베이스 date 타입과 매핑

-TemporalType.TIME : 시간을 데이터베이스 time 타입과 매핑
-TemporalType.TIMESTAMP : 날짜 + 시간을 데이터베이스 timestamp 타입과 매핑 | 필수 |

사용 방법은 다음과 같다.

// DATE
@Temporal(TemporalType.DATE)
private Date date;: 2023-10-25

// TIME
@Temporal(TemporalType.TIME)
private Date time;: 00:00:00

// TIMESTAMP
@Temporal(TemporalType.TIMESTAMP)
private Date timeStamp;: 2023-10-25 00:00:00:00

생략 할 경우 자바의 Date 타입과 가장 유사한 timestamp로 정의된다. 데이터베이스가 각기 다르더라도 방언 덕분에 코드는 변경하지 않아도 설정이 알아서 된다.

@Lob

📖데이터베이스의 BLOB, CLOB 타입과 매핑한다.

해당 어노테이션은 따로 지정할 수 있는 속성이 없다. 매핑하는 필드가 문자열이라면 CLOB으로 매핑하고 그렇지 않다면 BLOB으로 매핑한다.

여기서 잠시 CLOB과 BLOB에 대해 간단히 설명하고 넘어가자.

  • CLOB(Character Large Object) : 문자 기반의 큰 객체를 나타내며, 주로 텍스트 데이터를 저장하는데 사용된다.
  • BLOB(Binary Large Object) : 이진 데이터를 저장하는데 사용되며, 주로 이미지, 오디오, 비디오, 바이너리 데이터 등을 저장하는데 사용된다.

자바의 자료형으로 분류하면 다음과 같다.

  • CLOB : String, char[], java.sql.CLOB
  • BLOB : byte[], java.sql.BLOB

@Transient

해당 필드는 매핑하는 것을 희망하지 않을 경우 사용한다. 저장 및 조회도 하지 않기 때문에 임시로 어떤 값을 보관하고 싶을 때 활용하기도 한다.

@Access

📖JPA가 엔티티 데이터에 접근하는 방식을 지정한다.

두가지의 접근 방식이 있다.

  • AccessType.FIELD : 필드에 직접 접근하며 private로 선언하였더라도 접근이 가능하다. @Id가 필드에 있는 경우 해당 접근 방식은 생략 가능하다.
    @Entity
    public class Test{
    	@Id @GeneratValue // @Id 어노테이션이 필드에 있는 상태
    	private Long id;
    }
  • AccessType.PROPERTY : 접근자(getter, setter)를 통해서 접근이 가능하다. @Id가 프로퍼티에 있는 경우 해당 접근 방식은 생략 가능하다.
    @Entity
    public class Test{
    	@GeneratValue
    	private Long id;
    	...
    	@Id // @Id 어노테이션이 프로퍼티에 있는 상태
    	public Long getId(){
    	}
    }

두가지 접근 방식을 같이 사용하고 싶을 경우 각각 적용하고 싶은 필드 및 프로퍼티에 설정해서 사용하면 된다. 아래 예시를 보자.


마무리

회사에서 진행한 작은 프로젝트에 JPA를 사용했을 때를 생각해보면 다른 사람들의 블로그에서 그냥 이런 어노테이션을 사용하고, 저런 어노테이션을 사용해야 한다는 글만 보고 코드를 작성했었다. 그러던 와중에 책을 보면서 제대로 JPA에 대해서 습득해야겠다고 마음을 먹고 공부를 하는 지금 확실히 모르는 것을 그냥 사용하는 것과 왜 사용해야하는지 이유를 알고 뭐가 더 적절한지를 판단할 수 있는 상태로 코드를 작성하는 것에는 너무 큰 차이가 있다는 것을 느낀다.

동작만하는 코드가 아니라 논리적인 사고를 통한 합당한 근거가 있는 코드를 작성하는 것이 재미있다는 것을 느끼게 되는 시기인 것 같다.

그럼 이만.👊🏽

profile
서핑하는 개발자🏄🏽

0개의 댓글