1. 프로젝트에 Spring Data JPA 적용하기

1. 의존성 등록하기

dependencies {
    compile('org.springframework.boot:spring-boot-starter-web')
    compile('org.projectlombok:lombok')
    annotationProcessor("org.projectlombok:lombok")
    compile('org.springframework.boot:spring-boot-starter-data-jpa')//...1
    compile('com.h2database:h2')//...2

    testCompile('org.springframework.boot:spring-boot-starter-test')
}
  1. spring-boot-starter-data-jpa
  2. h2

2. domain 패키지 생성

domain 패키지는 도메인을 담을 패키지

여기서 도메인이란 게시글, 댓글, 회원, 정산, 결제 등 소프트웨어에 대한 요구사항 혹은 문제 영역

기존에 MyBatis와 같은 쿼리 매퍼를 사용했다면 dao 패키지를 떠올리겠지만 dao 패키지와는 조금 결이 다르다.

그간 xml에 쿼리를 담고, 클래스는 오로지 쿼리의 결과만 담던 일들이 모두 도메인 클래스라고 불리는 곳에서 해결된다.

3. posts 패키지와 Posts 클래스 생성

Posts 클래스는 실제 DB의 테이블과 매칭될 클래스이며 보통 Entity 클래스라고도 한다.

JPA를 사용하면 DB 데이터에 작업할 경우 실제 쿼리를 날리기보다는, 이 Entity 클래스의 수정을 통해 작업한다.

Tip)

어노테이션 순서를 주요 어노테이션을 클래스에 가깝게 두자.

이렇게 어노테이션을 정렬하는 기준은 다음과 같다.

@Entity는 JPA의 어노테이션이며, @Getter와 @NoArgsConstructor는 롬복의 어노테이션

롬복은 코드를 단순화시켜 주지만 필수 어노테이션은 아니다.

그러다 보니 주요 어노테이션인 @Entity를 클래스에 가깝게 두고, 롬복 어노테이션을 그 위로 두었다.

이렇게 하면 이후에 코틀린 등의 새 언어 전환으로 롬복이 더 이상 필요 없을 경우 쉽게 삭제할 수 있다.

Posts 클래스의 코드

package com.jojoldu.book.springboot.domain.posts;

import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.*;

@Getter //...6
@NoArgsConstructor //...5
@Entity //...1
public class Posts {
    @Id //...2
    @GeneratedValue(strategy = GenerationType.IDENTITY) //...3
    private Long id;

    @Column(length = 500, nullable = false) //...4
    private String title;

    @Column(columnDefinition = "TEXT", nullable = false)
    private String content;

    private String author;

    @Builder //...7
    public Posts(String title, String content, String author) {
        this.title = title;
        this.content = content;
        this.author = author;
    }
}

Posts 클래스에는 JPA에서 제공하는 어노테이션들

  1. @Entity

    @Table

  2. @Id

  3. @GeneratedValue

  4. @Column

  5. @NoArgsConstructor

  6. @Getter

  7. @Builder

❗ Entity 클레스에서는 절대 Setter 메소드를 만들지 않습니다.❗

단, 해당 필드의 값 변경이 필요하면 명확히 그 목적과 의도를 나타낼 수 있는 메소드를 추가해야만 한다.

이유는 Setter 메소드가 들어가게 되면 언제 어디서 변해야하는지 코드상으로 명확하게 구분할 수가 없어, 기능 변경시 복잡해지기 때문이다.

//잘못된 사용 예
public class Order {
	public void setStatus (boolean status) {
		this.status = status;
  }
}

public void 주문서비스의_취소이벤드() {
	order.setStatus(false);
}
//올바른 사용 예
public class Order {
	public void cancelOreder() {
		this.status = false;
  }
}

public void 주문서비스의_취소이벤드() {
	order.cancelOrder();
}

그러면, 어떻게 값을 채워 DB에 삽입하는 걸까 ??

기본적인 구조는 생성자를 통해 최종값을 채운 후 DB에 삽입하는 것이며,