JPA Entity의 기본속성

이종윤·2022년 2월 5일
0

Spring JPA

목록 보기
7/23

🤔Entity

도매인 객체인 Entity는 실습을 통해 공부해보자.

✅ GenerationType 이 뭘까?

@Entity // 해당 객체가 JPA에서 관리하고 있는 객체인것을 정의.
public class User {

    @Id // 엔티티에는 식별자가 필요한데 @ID로 표현.
    @GeneratedValue // GenerationType (IDENTITY, SEQUENCE, TABLE, AUTO)
    private long id;
    /*IDENTITY
    * DB에서 AUTOINCREMENT를 이용해 자동으로 ID값이 늘어나는 것 처럼 id값을 먼저 insert 시킨다.
    * 그래서 트랜젝션이 끝나기 전에 , 즉 롤백 된다하더라도 이미 insert 되어 있어서 마치 이빨빠진것 처럼 중간에 비는 현상이 일어난다.

    /*SEQUENCE
    * Sequence는 오라클, postqre에서 쓰는데 인서트를 할 때 시쿼스로부터 증가된 id 값을 받아서 실제 id값에 넣는 방식이다.
    */

    /*TABLE
    * DB종류에 상관없이 Table에 id값을 저장해 두고 추출하여 이용한다.
    */

    /*AUTO
    * 지정하지 않으면 AUTO를 쓴다. 그러면 각 DB 적합한 값을 자동으로 넘겨주는데, DB 의존성이 없이 코딩할수 있다.
    * 하지만 일반적으로 DB는 고정해서 사용하는 경우가 많아서 구체적인 값을 지정해 사용하는경우가 많다.
    */
    
	...
    ...
}
GenerationType을 설정해보자.

✅ GenerationType (Table)

@Table(name = "user_legacy")
public class User {
	...
    ...
    ...
}

👉 Test를 해보면

    create table user_legacy (
       id bigint not null,
        created_at timestamp,
        email varchar(255),
        name varchar(255),
        updated_at timestamp,
        primary key (id)
    )

👉 Test가 수행될때 table을 만드는걸 볼 수 있다.

✅ @indexes(인덱스) 와 @uniqueConstraints(제약조건)

@Table(name = "user" ,indexes = {@Index(columnList = "name")}, uniqueConstraints = {@UniqueConstraint(columnNames = {"email"})})
public class User {

👉 위와 같이 indexes와 uniqueConstraints 설정해 주면 ddl이 생성될때 index가 생성이 되고, 제약조건이 생성된다.

Hibernate: create index IDXgj2fy3dcix7ph7k8684gka40c on user (name)
Hibernate: 
    
    alter table user 
       add constraint UKob8kqyqqgmefl0aco34akdtpe unique (email)

🤚 하지만 위와같이 표시한다고 해서 실제 DB와 똑같아 지는건 아니다. JPA를 이용해서 DB DDL을 생성할때는 적용되지만, 일반적으로 많이 사용하는 select delete update 같은 쿼리에 아무런 적용이 안된다. 즉, 실제 DB에 index가 없는데 JPA에서 설정해준다고 해서 실행이 되지 않는다는 거다.

✅ @Colume

    @Id // 엔티티에는 식별자가 필요한데 @ID로 표현.
    @GeneratedValue // GenerationType (IDENTITY, SEQUENCE, TABLE, AUTO)
    private long id;
    
    @NonNull
    private String name;

    @NonNull
    @Column(updatable = false, insertable = false)
    private String email;

    @Column(name ="crtd_at", nullable = false,unique = true)
    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;

👉 Column의 name을 지정하는건 요즘에는 안한다. 왜냐면 왠만하면 명시적으로 DB의컴럼이름과 엔티티의 변수 이름을 같게 하기때문이다. 하지만 DB컬럼이름과 엔티티의 변수 이름이 다르면 name을 이용해여 mapping해준다.

👉 nullable 은 말 그대로 notNull제약을 DDL에 추가해 주는 것 이다. 위에 @indexes @uniqueConstraints와 같이 실제 DB에 적용 되는건 아니지만, 실제 서비스를 만들때 notnull표시는 정말 유용하기때문에 명시적으로 적어주는것이 좋다.

👉 unique는 중복 불가인거 다 알지? 그럼 @Table에 있는 제약사항 uniqueConstraints와 다른점은 뭘까?
🤔 uniqueConstraints 는 테이블의 복합 컬럼, 즉 2 속성을 묶어서 unique를 설정하는 것이고, 컬럼하나만 지정하고 싶을때는 그 변수 위에 unique = true 하는 것이다.

쉽게 말하면 이런거 아닌가?
👇복합 유니크 ex          👇 그냥 유니크 ex
반 | 번호                     전화번호                
1  |  3                     01012341234
1  |  2                     01012341235
1  |  3                     01012341236
1  |  4                     01012341237

✅ @Column의 insertable 과 updatable

😮 insertable,updatable 이 두놈은 다른 설정과는 다르게 DML에도 영향을 끼친다.

    @Column(insertable = false)
    private LocalDateTime createdAt;
    @Column(updatable = false)
    private LocalDateTime updatedAt;
@Test
    void insertAndUpdateTest(){
        /*insert*/
        User user =new User();
        user.setName("martin");
        user.setEmail("martin2@fast.com");

        userRepository.save(user);

        /*update*/
        User user2 = userRepository.findById(1L).orElseThrow(RuntimeException::new);
        user2.setName("marrrrrtin");

        userRepository.save(user2);

    }

👉 위와 같이 createdAt 에는 (insertable = false)를 updatable에는 (updatable = false)를 지정해 줬다. 결과를 보자.

    insert 
    into
        user
        (email, name, updated_at, id) 
    values
        (?, ?, ?, ?)
        

    update
        user 
    set
        created_at=?,
        email=?,
        name=? 
    where
        id=?

위의 로그처럼 insert문에는 createdAt 애트리뷰트가 빠졌고 update문에는 updated_at가 빠진걸 알 수 있다.

✅ @Transient
Entity는 Data객체기 때문에 DB레코드 값을 그대로 반영한다. 하지만 객체로써의 역할도 하기 때문에 DB레코드와 별개의 Data를 가지고 싶은 Needs가 발생한다. 그때 트랜지언트를 쓴다.

    @Transient
    private String testData;

이렇게 하면 ddl에도 안들어가고 dml에도 안들어간다. 영속성처리에 제외되기 때문이다.즉 DB레코드에 처리가 안된다.

🤔🤔ENUM Type?

Enum 타입은 DB에는 0,1, 순서대로 들어간다. 즉, 남자,여자 객체가 차례로 있어도 DB에선 0,1으로 맵핑된다는 것이다. 그래서 항상 Enum을 쓰기 보단 그냥 String 타입을 썻다. Jpa에서도 그렇게 해야할까?
실습해보자.
✅ enum type 클래스생성

public enum Gender {
    MALE,
    FEMALE
}

✅ User 엔티티에 이넘타입 gender 사용.

private Gender gender;

✅ nativeQuery 쿼리를 아직 안배웠지만, 일단 UserRepository에 연습용으로 써보자.

    @Query(value = "select * from user limit 1;", nativeQuery = true)
    Map<String, Object> findRawRecord();

✅ 그리고 Test

 @Test
    void enumTest() {
        User user = userRepository.findById(1L).orElseThrow(RuntimeException::new);
        user.setGender(Gender.MALE);

        userRepository.save(user);

        userRepository.findAll().forEach(System.out::println);

        System.out.println(userRepository.findRawRecord().get("gender"));
    }


위에서 언급했다 싶이 MALE의 젠더를 보니 0이라는 결과가 나온다. 자 이제 Enum Data위에

	@Enumerated(value = EnumType.STRING)
	private Gender gender;

@Enumerated(value = EnumType.STRING)
다시 Test하면


이제 숫자가 아닌 문자열로 출력된다.
이거 정말 중요하다. 😡

profile
OK가자

0개의 댓글