Entity와 Table

반응형
반응형

Jpa를 공부하다보면 제일 먼저 Entity를 만나볼 수 있습니다.
이걸 보고 있으면 객체이면서 테이블 같은 오묘한 기분을 느낄 수 있습니다.
이는 사실 JPA의 특징의 영속성과 큰 연관이 있습니다.

영속성
영속성이라는 것은 한 객체가 생성 작업이 종료 되었음에도 지속적으로 존재하는 상태라는 것을 말합니다.
물론 억지로 close같은 걸 이용하거나 프로그램을  강제로 종료 시킨다면 소멸 되겠지만
그렇지 않으면 웬만하면 죽지 않습니다.
그게 바로 영속성입니다. 근데 어째서 JPA에서는 영속성이라는 용어를 사용하면서 관리를 하는 걸까요?

그건 바로 객체를 이용해서 테이블을 생성하고 이용하고 싶기 때문이라고 생각합니다.
물론 마이바티스 처럼 자바에서 쿼리를 작성해서 DB에 연동시키는 게 더 좋을거라 생각할지도 모릅니다.
어떻게 보면 그렇게 하는것이 더 개발 속도 측면에서 더 빠르다고 느낄 지도 모릅니다.
왜냐하면 쿼리만 작성하면 되기 때문이죠.
하지만 생각해보세요. 영속성이라는 것을 사용하게 되면 어찌되었든 테이블이 아니라 다른 곳에 데이터를 저장을 해야 됩니다.
그래야 JPA가 그 데이터를 조작할 수 있기 때문이죠. 물론 마이바티스보다 1가지 이상의 작업을 더 해야되기 때문에 간단한 쿼리를 작성을
해야 된다면 마이바티스가 성능이 더 좋을지도 모릅니다.
하지만 1이상의  작업을 더 해야된다는 이야기는 어떻게 보면 잘 동작하는 공장과 같다고 생각이 듭니다.
인형 하나를 만든다고 가정했을때, 한명이 만드는 것이 여러명이 함께 만드는 것보다 더 빠를 수 있습니다. 하지만 인형이 하나가 아니라 여러개 라면 얘기는 달라집니다. 공장에서는 이러한 환경이 구축이 되었기 때문에 추가적으로 인형을 하나를 더 만드는 것은 일도 아니게 되어집니다. 물론 이 비유는 JPA와 전혀 상관이 없는 비유입니다. 제가 말하고 싶은 점은 이러한 환경을 미리 구축을 해놓은 다면 쿼리 하나를 만들때는 타 제품보다 느려도 쿼리가 그 이상이라면 더 효율적이지 않을까요? 물론 빠르다고는 말 못하겠습니다. 왜냐하면 제가 이에대한 전문가가 아니기 때문이죠.

이에 대해서는 더 할 말이 많지만 이에 대한 주제가 아니기 때문에 넘어가도록 하죠.
아무튼 JPA는 객체를 만들게 되면 @Entity라는 어노테이션을 붙이게 되면 JPA는 이 객체를 이제부터 JPA가 관리를 하겠다고 선언합니다. 그러면 언제든지 이 객체를 언제든지 영속화를 시킬 수 있습니다.

@Entity
public class Hello {

}

 
 제일 먼제 이 객체에 꼭 필요한 녀석이 있습니다. 그건 바로 Id값입니다. Id값은 db세계에서는 pk라고 부른다고 합니다.
아무튼 실 db세계에서는 pk값이 반 필수 지만 이쪽 세계에서 몸담고 있는 JPA는 이 값을 강제적으로 pk를 지정하게 했습니다.
이로써 이 객체로 만들어진 db는 pk값을 가진다는 사실을 알 수 있습니다.
여기서 궁금한게 생겼습니다.
과연 pk를 입력하지 않는 Entity는 어떤 에러를 던질까? 당연한 이야기 겠지만 일단은 컴파일에러를 던져주겠죠?
바로 No identifier specified for entity라는 에러를 던져줍니다. 이말은 식별자를 넣으라는 뜻입니다.

일반적으로 식별자는 Long을 많이 이용합니다. 왜냐하면 이게 관행이면서 과거에 엄청난 사건들이 있었기 때문이라 생각합니다.
아니면 Inteager,String등을 사용해두 됩니다.  근데 어째서 int같은 primitive 타입을 사용하지 않고 Object 타입을 사용하는 이유는 어디까지나 null때문입니다. 객체가 0인건 말이 되지 않죠. 객체가 없는건 말이되도..

만약, 물론 직접 ID값을 입력해도 되겠지만
mysql의 auto increament처럼 자동으로 값을 지정하는게 있으면 좋을 것 같습니다.

@Entity
public class Hello {
  @Id @GeneratedValue
  private Long id;
}

이렇게 하면 값을 자동으로 1씩 증가됨을 알 수 잇습니다.
db마다 값을 올리는 방식이 조금씩 다릅니다. 이러한 점을 해결하기 위해 JPA에서는 총 3가지 방식으로 이를 제공하고 있습니다.

1. @GeneratedValue (strategy =IDENTITY) 
2. @GeneratedValue(strategy=SEQUENCE) 
3. @GeneratedValue(strategy=TABLE)

위에서 부터 하나씩 설명하자면, 식별자 전략으로 그냥 1씩 증가시키는 방법을 말합니다.
근데 이 방법은 약간의 문제가 있습니다.
일반적으로 jpa는 commit 할때 db에 반영이 되어집니다. 하지만 이 방법은 애초에 객체에서 1씩 증가는 것이 아니라 테이블이 1씩 증가하는 형태이기 때문에 영속화 상태가 될때 값을 알 고 있어야 됩니다. 근데 commit될때 id값이 반영이 되어집니다.
여기서 이 방식에 문제가 발생했습니다. 그러면 이 방법은 사용하면 안되는 것일까요? JPA에서는 이 방식에 대해서는 영속화상태로 만들때 insert쿼리를 날려버립니다. 즉, flush를 쓴다는 말이죠. 
다행스럽게도 성능적인 큰 이슈가 없다고 합니다. JPA 화이팅!

어떻게 보면 2번째 방식과 3번째 방식은 유사점이 굉장히 많습니다. 다른점은 테이블을 만들어서 사용하냐 아니냐에 차이라 생각합니다.
3번째 방식은 2번째 방식을 흉내낸 방식이기 때문에 성능이 굉장이 떨어집니다. 
이에 대해서는 더 말할 기회가 있다면 다음에 하도록 하죠. 왜냐하면 이제 그만 하고 싶기 때문이죠.
(네 사실 제가 설명하기 어려워서 그래요 )

아무튼 JPA는 이렇게 3가지 방식을 제공하고 있고 이게 가능한 이유는 방언때문입니다. 

그러면 이렇게 id값을 만들었다면, 데이터를 넣어야져.
데이터는 어떠한 방식이든 넣으면 됩니다.
심지어 get, set 없이

  @Id
  Long id;
  String name;

이렇게 만들어도 insert쿼리가 나가긴 합니다. 물론 이 방식은 캡슐화에 맞지 않기때문에 사용은 안하는게. 좋을 것 같습니다.
굳이 get/set이 아니여도 객체에 값을 넣는 어떠한 방법이라면 뭐든지 가능합니다.

진짜 final은 불가능한걸까요?
final로 하면 값이 들어가지 않는다는 이야기가 있던데 생성자를 이용하면 가능할것 같은데..
그거 제가 해보겠습니다.

  @Id
  private final Long id;
  private final String name;

  public Members(Long id, String name) {
    this.id = id;
    this.name = name;
  }

Hibernate: 
    /* insert helloJava.Members
        */ insert 
        into
            Members
            (name, id) 
        values
            (?, ?)

이렇게 하면 값이 들어가지는 군요. 여기에다 @Builder를 붙이면 생각만해도 기분이 좋아집니다.
이제 데이터를 각자의 입맛에 맞게 맞춰서 만들면 되겠습니다.!

 

'JPA' 카테고리의 다른 글

JPQL 기본 문법  (0) 2021.12.18
값 타입 작성 방법  (0) 2021.12.12
Proxy?  (0) 2021.12.04
상속하는 방법?  (0) 2021.11.27
연관관계의 주인을 바꾸면 무슨일이 발생할까?  (0) 2021.10.30
Entity와 Table  (0) 2021.10.16

댓글(0)

Designed by JB FACTORY