서로 지향하는 바가 다른 객체지향 프로그래밍 언어와 관계형 데이터베이스의 중간에서 패러다임을 일치시켜주기 위한 언어
JPA: 인터페이스, 자바 표준 명세서
구현체: Hibernate, Eclipse Link
스프링에서 JPA를 사용할 때는 이 구현체들을 직접 다루지 않고, 구현체들을 좀 더 쉽게 사용하고자 추상화시킨 Spring Data JPA
라는 모듈을 이용한다.
Posts.java
package com.geniushyeon.springboot.domain.posts;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@Getter // setter 사용 X
@NoArgsConstructor
@Entity // 테이블과 링크될 클래스임을 나타냄
public class Posts {
@Id // pk
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(length = 500, nullable = false)
private String title;
@Column(columnDefinition = "TEXT", nullable = false)
private String content;
private String author;
@Builder
public Posts(String title, String content, String author) {
this.title = title;
this.content = content;
this.author = author;
}
}
Setter가 없는 상황에서 DB에 값을 삽입할 때
생성자나 빌더나 생성 시점에 값을 채워주는 역할은 똑같지만, 생성자의 경우 지금 채워야 할 필드가 무엇인지 명확하게 지정할 수 없다.
빌더를 사용하게 되면 어느 필드에 어떤 값을 채워넣는지 명확하게 인지할 수 있다.
PostsRepository.java
package com.geniushyeon.springboot.domain.posts;
import org.springframework.data.jpa.repository.JpaRepository;
public interface PostsRepository extends JpaRepository<Posts, Long> {
}
인터페이스로 생성한 후 JpaRepository<Entity, PK>
를 상속하면 기본적인 CRUD 메소드가 자동으로 생성됨
PostsRepositoryTest.java
package com.geniushyeon.springboot.domain.posts;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@ExtendWith(SpringExtension.class)
@SpringBootTest
public class PostsRepositoryTest {
@Autowired
PostsRepository postsRepository;
@AfterEach
public void cleanup() { // 매 테스트 메소드 후 실행
postsRepository.deleteAll();
}
@Test
public void 게시글저장_불러오기() {
// given
String title = "테스트 제목";
String content = "테스트 본문";
postsRepository.save(Posts.builder()
.title(title)
.content(content)
.author("geniushyeon@github.com")
.build());
// when
List<Posts> posts = postsRepository.findAll();
// then
Posts post = posts.get(0);
assertThat(post.getTitle()).isEqualTo(title);
assertThat(post.getContent()).isEqualTo(content);
}
}
application.properties 작성
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect
spring.jpa.properties.hibernate.dialect.storage_engine=innodb
spring.datasource.hikari.jdbc-url=jdbc:h2:mem:testdb;MODE=MYSQL
spring.datasource.hikari.username=sa
Web, Service, Repository, Dto, Domain 5가지 레이어에서 비즈니스 처리를 담당해야 할 곳은 Domain
이다.
서비스 메소드는 트랜잭션
과 도메인 간의 순서
만 보장해 준다.
@RequiredArgsConstructor
영속성 컨텍스트: 엔티티를 영구 저장하는 환경
JPA의 핵심 내용은 엔티티가 영속성 컨텍스트에 포함되어 있느냐 아니냐로 갈린다.
Entity 객체의 값만 변경하면 별도로 update 쿼리를 날릴 필요가 없다.