이전 포스팅에 이어 @Column과 @Transient를 정리.

 

정리전 예제 환경은 아래와 같다.

  • Intelli J
  • SpringBoot 2.6.2
  • Lombok
  • Gradle 7.3.2

1. @Column

@Column 어노테이션 속성을 먼저 확인해보면 name, unique, nullable, insertable, updatable, columnDefinition 등등이 존재한다.

name 속성의 경우 해당 컬럼의 이름을 지정해주는 속성이다.

 

처음부터 새로 만드는 프로젝트의 경우 별도로 지정해주지 않는것이 좋지만 DB는 유지하는 상태에서 리빌딩하는 경우 과거 네이밍 규칙으로 인해 가독성이 떨어지는 네이밍에 대해 수정하는 경우 사용하면 좋다.

 

강의에서의 예를 든것으로 createdAt을 예전에는 crtdat 이런 식으로 줄여서 사용하는 경우가 많았다고 한다.

그럼 이 crtdat을 DB에서는 유지하지만 코드에서는 createdAt으로 바꿔 가독성이 좋아지도록 변경할 수 있다는 것이다.

 

@Column(name = "crtdat")
private LocalDateTime createdAt;

이렇게 사용할 수 있고 어노테이션의 name 속성에 DB 컬럼명을 넣어주면 된다.

 

 

그리고 다음으로 많이 사용하는것이 nullable이다.

일반적인 쿼리를 사용하지 않는 경우에는 사전에 걸러주는 validation 역할을 하지 않는다.

DDL 쿼리를 자동으로 생성할 때 not null 필드를 만들어줄때 사용한다.

default 값은 true이기 때문에 따로 설정하지 않는다면 기본적으로 null을 허용하지만 false로 설정하게 되면 DDL 쿼리가 동작해 생성할 때 해당 컬럼을 not null로 생성한다.

@Column(nullable = true)
private LocalDateTime createdAt;

 

 

unique 속성은 @Table 어노테이션의 Unique Constraints와 동일한 역할을 하지만 @Table에서의 UniqueConstraints는 여러 컬럼들을 엮어 Unique 제약조건을 설정하는 것이라고 한다면 @Column에서의 unique 속성은 해당 컬럼 하나에 대한 제약조건을 설정할 때 사용한다.

default는 false로 되어있고 true로 설정하게 되면 unique 제약조건을 생성하게 된다.

하지만 이 경우 제약조건명이 랜덤생성되기 때문에 추천하진 않는다고 한다.

 

@Column(unique = true)
private LocalDateTime createdAt;

 

columnDefinition은 컬럼의 정보를 직접 지정할 수 있는 속성이다.

createdAt은 DDL이 생성될때 timestamp로 생성되고 있다.

 

그런데

@Column(columnDefinition = "datetime")
private LocalDateTime createdAt;

이렇게 columnDefinition을 사용하면 datetime으로 생성되는것을 볼 수 있다.

그리고 하나더.

default 값을 여기서 설정할 수도 있다.

 

createdAt의 경우 데이터가 insert되는 시점마다 현재 시간이 들어가야 한다.

그때마다 코드에서 직접 처리하도록 하게 되면 누락되는 부분도 생길것이고 모든 데이터에 대해 createdAt을 사용한다고 하면 수많은 엔티티의 insert 처리를 할때마다 다 데이터를 넣어 처리해줘야 한다.

 

그래서 DB 를 설계할때도 default 값으로 들어가도록 설정하는 경우가 있는데 이걸 columnDefinition으로 설정할 수 있다.

 

@Column(columnDefinition = "datetime default now()")
private LocalDateTime createdAt;

이렇게 설정하게 되면 DDL에서 쿼리를 확인했을 때 created_at datetime default now()로 생성되는것을 볼 수 있다.

 

여기서 주의해야할 점이 있따.

그럼 columnDefinition을 사용하지 않았을때 timestamp라는 데이터 타입이 기본적으로 생성되었으니까

데이터타입을 굳이 바꿔줄게 아니라면 default만 사용해도 되지 않을까??

 

@Column(columnDefinition = "default now()")
private LocalDateTime createdAt;

그래서 이렇게 테스트를 실행하고 DDL 쿼리를 확인해보면

created_at default now()

이렇게 테이터 타입이 사라진 것을 볼 수 있다.

 

왜 이렇게 되는지에 대해서는 Ejb3Column.java에서 확인할 수 있다.

 

코드가 좀 길게 되어있는데 이부분에서 확인이 가능하다

columnDefinition이 비어있다면 sqlType은 null이 된다.

이때 jpa에서 entity에 명시한 타입에 따라 데이터 타입을 넣어준다고 볼 수 있다.

그럼 columnDefinition이 비어있지 않다면??

columnDefinition의 값이 그대로 applyGlobalQuoting에 인자로 넘어가기 때문에 validaition 없이 값 그대로 들어간다고 볼 수 있다.

 

그래서 아예 작성하지 않는다면 알아서 타입을 잡아주지만 그렇지 않다면 있는 그대로 넘겨버리기 때문에 꼭 데이터 타입을 같이 적어줘야 한다.

 

 

table 속성은 하나의 엔티티를 두개 이상의 테이블에 매핑할 때 사용한다.

이걸 사용하게 되면 해당 필드를 다른 테이블에 매핑할 수 있다.

타입은 String 타입으로 매핑하고자 하는 테이블을 명시하면 된다.

 

하지만 @SecondaryTable 어노테이션을 사용하야 하고 @SecondaryTable은 위에서 말한것 처럼 하나의 엔티티를 두개 이상의 테이블에 매핑하기 위해 사용하는 어노테이션이다.

 

아무래도 하나의 엔티티가 두개의 테이블에 매핑되다보니 엔티티 하나를 조회하는데 테이블 2개를 조회해야 하기 때문에 최적화가 어렵다고 한다.

그리고 잘 사용하지도 않는다고 한다.

 

이 table 속성에 대한것은 레퍼런스에서 확인.

 

 

length 속성은 문자 길이 제약조건이다.

쉽게 보통 DB 설계할때 VARCHAR(255) 이렇게 만드는것처럼 문자열 길이를 명시한다.

default는 255이다.

 

@Column(length = 20)
private String name;

이렇게 실행하게 되면 name 컬럼은 varchar(20)이 된다.

 

 

precision과 scale은 BigDecimal이나 BigInteger에서 사용한다.

precision은 소수점을 포함한 전체 자리수를, scale은 소수의 자리수를 명시한다.

 

 

 

그럼 여기서 아직 확인하지 않은 속성이 insertable과 updatable인데 이 두 속성을 빼둔 이유는 위의 속성들은 DDL 생성시에 적용되지만 이 두 속성은 DML에도 영향을 끼치기 때문이다.

 

의미 그대로 엔티티 저장시, 수정시에 영향을 끼치는 속성으로 insertable은 엔티티 저장시에 이 필드도 같이 저장을 하고자 할때 사용하며 updatable은 엔티티 수정시에 같이 수정하고자 할때 사용한다.

 

둘다 동일하게 false로 설정하게 되면 DB에 적용되지 않고 false는 읽기전용으로 사용하고자 할때만 사용한다.

default는 true로 설정되어 있다.

 

@Column(updatable = false, columnDefinition = "datetime default now()")
@CreatedDate
private LocalDateTime createdAt;

@Column(columnDefinition = "datetime default now()")
@LastModifiedDate
private LocalDateTime updatedAt;

이런 형태로 설정하게 되는데 createdAt은 처음 insert 시에만 저장되어야 하기 때문에 updatable을 false로 설정해 수정이 발생할때는 createdAt은 수정하지 않게 된다.

그리고 updatedAt은 처음 insert시에도 같이 저장되어야 하지만 수정될때마다 계속해서 수정되어야 하기 때문에 아무것도 명시하지 않게 되면 default가 true이기 때문에 insertable = true, updatable = true 상태가 되어 저장시, 수정시 모두 처리하게 된다.

 

 

 

 

1. @Transient

@Transient 어노테이션은 DB에 존재하지 않지만 객체로서 사용하고 싶을 때 붙여 사용한다.

이 어노테이션이 붙어있는 필드는 영속성 처리에서 제외가 되기 때문에 DB 데이터에 반영이 되지 않고 해당 객체와 생명주기를 같이하게 되는 값이 된다.

 

이전에 설명한 insertable과 updatable의 false 기능에 추가적으로 select도 불가능하고 auto-ddl을 수행할때도 DDL에 반영되지 않도록 하는 어노테이션이라고 보면된다.

 

말그대로 DB에 전혀 영향을 주지 않고 쿼리문에도 영향을 끼칠 수 없는 단순한 객체로 만들어주는 어노테이션이다.

 

 

 

Reference

  • 패스트캠퍼스 java/spring 초격차 패키지 Spring Data JPA
  • @Column의 table 속성

 

 

JPA - 하나의 엔티티에 다수 테이블 매핑(@SecondaryTable,@SecondaryTables)

JPA - 하나의 엔티티에 다수 테이블 매핑(@SecondaryTable,@SecondaryTables) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Entity @Table(name = "BOARD") @SecondaryTable(name = "BOARD_DETAIL",        ..

coding-start.tistory.com

 

'Spring' 카테고리의 다른 글

JPA Entity Listener 2  (0) 2022.03.17
JPA Entity Listener 1  (0) 2022.03.16
Jpa Entity 기본 Annotation 1 (@GeneratedValue, @Table)  (0) 2022.03.14
JPA Enum 적용  (0) 2022.02.19
JPA QueryMethod 2 (where 절 조건 추가)  (0) 2022.02.17

+ Recent posts