플레이데이터 - 38일차 Spring Boot Framework(3)

Kim Hyen Su·2023년 8월 23일

✅엔티티 설계

  • Spring Data JPA를 사용하면 데이터베이스에 테이블을 생성하기 위해 직접 쿼리를 작성할 필요가 없다.
  • 위 기능을 가능하도록 해주는 것이 엔티티이다.
  • 엔티티는 데이터베이스의 테이블에 대응하는 클래스이다.
import jakarta.persistence.*;
import java.time.LocalDateTime;

@Entity
@Table(name="product")
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long number;

    @Column(nullable=false)
    private String name;

    @Column(nullable=false)
    private Integer price;

    @Column(nullable=false)
    private Integer stock;

    private LocalDateTime createdAt;

    private LocalDateTime updatedAt;

    public Long getNumber() {
        return number;
    }

    public void setNumber(Long number) {
        this.number = number;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getPrice() {
        return price;
    }

    public void setPrice(Integer price) {
        this.price = price;
    }

    public Integer getStock() {
        return stock;
    }

    public void setStock(Integer stock) {
        this.stock = stock;
    }

    public LocalDateTime getCreatedAt() {
        return createdAt;
    }

    public void setCreatedAt(LocalDateTime createdAt) {
        this.createdAt = createdAt;
    }

    public LocalDateTime getUpdatedAt() {
        return updatedAt;
    }

    public void setUpdatedAt(LocalDateTime updatedAt) {
        this.updatedAt = updatedAt;
    }
}

엔티티 관련 기본 어노테이션

@Entity

  • 클래스가 엔티티임을 명시하기 위한 어노테이션.
  • 해당 클래스의 인스턴스는 매핑되는 테이블에서 하나의 레코드를 의미한다.

@Table

  • 클래스명과 테이블명을 다르게 지정할 경우 사용하는 어노테이션.

@Id

  • 지정 필드를 테이블의 기본값 조건의 컬럼으로 생성 시 사용하는 어노테이션.
  • 모든 엔티티는 반드시 @Id(기본키) 지정을 해줘야 한다.

GeneratedValue

  • 해당 필드의 값을 어떤 방식으로 자동 생성할지 결정 시 사용하는 어노테이션.
    • GeneratedValue를 사용하지 않는 방식(직접 할당)
      • 애플리케이션에서 자체적으로 고유한 기본값을 생성할 경우 사용.
        • 내부에 정해진 규칙에 의해 기본값을 생성하고 식별자로 사용.
          - AUTO
      • @GeneratedValue 기본 설정값(default)
        • 기본값을 사용하는 데이터베이스에 맞게 자동 생성함.
          - IDENTITY
      • 기본값 생성을 데이터베이스에 위임하는 방식.
        • 데이터베이스의 AUTO_INCREMENT를 사용하여 기본값을 생성.
          - SEQUENCE
      • @SequenceGenerator 어노테이션으로 식별자 생성기를 설정하고 이를 통해 값을 자동 주입받음.
        - TABLE
      • 어떤 DBMS를 사용하더라도 동일하게 동작하기를 원할 경우 사용.
        • 식별자로 사용할 숫자의 보관 테이블을 별도로 생성하여 엔티티를 생성 시마다 값을 갱신하며 사용함.
        • @TabkeGenerator 어노테이션으로 테이블 정보를 설정.

@Column

  • 테이블의 컬럼 관련 설정을 위해 사용하는 어노테이션.
  • 자주 사용하는 요소
    • name : 컬러명 설정, 명시하지 않으면 필드명으로 설정.
    • nullable : 레코드 생성 시 null 처리 가능 여부 설정.
    • length : 데이터베이스에 저장하는 데이터의 최대 길이 설정.
    • unique : 해당 컬럼 unique로 설정.

@Transient

  • 엔티티 클래스에 정의된 필드 중 테이블에서 필요 없을 경우 사용하여 테이블로 매핑되지 않도록 설정하기 위한 어노테이션.

✅레포지토리 인터페이스 설계

  • Spring Data JPA는 JpaRepository를 기반으로 더욱 쉽게 데이터베이스를 사용할 수 있는 아키텍처를 제공.

레포지토리 인터페이스 생성

  • 레포지토리는 엔티티가 생성한 테이블(데이터베이스)에 접근하는데 사용된다.
import com.springboot.jpa.data.entity.Product;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ProductRepository extends JpaRepository<Product,Long> {    
}
  • JpaRepository 인터페이스를 상속받는다.
  • 상속 시, 대상 엔티티와 기본값 타입을 지정해야 한다.

레포지토리 메서드의 생성 규칙

  • 레포지토리에서 몇 가지 명명규칙에 따라 커스텀 메서드도 생성 가능.
  • FindBy : SQL문의 where절 역할을 수행하는 구문. Ex) findByName(String name)
  • AND, OR : 조건을 여러 개 설정하기 위해 사용. Ex) findByNameAndEmail(String name, String email)
  • Like/NotLike: SQL문의 like와 동일한 기능을 수행.
  • StartsWith/StartingWith: 특정 키워드로 시작하는 문자열 조건을 설정.
  • EndsWith/EndingWith: 특정 키워드로 끝나는 문자열 조건을 설정.
  • IsNull/IsNotNull: 레코드 값이 Null이거나 Null이 아닌 값을 검색.
  • True/False: Boolean 타입의 레코드를 검색할 때 사용.
  • Before/After: 시간을 기준으로 값을 검색.
  • LessThan/GreaterThan: 특정 값을 기준으로 대소 비교를 할 때 사용.
  • Between: 두 값 사이의 데이터를 조회.
  • OrderBy: SQL문에서 order by와 동일한 기능 수행.
  • countBy: SQL문에서 count와 동일한 기능을 수행.

✅DAO 설계

  • 데이터베이스에 접근하기 위한 로직을 관리하기 위한 객체.
  • 즉, 비지니스 로직의 동작 과정에서 데이터 조작하는 기능은 DAO 객체가 수행.
  • 다만, Spring Data JPA에서 DAO의 개념은 레포지토리 가 대체함.
  • 일반적으로 데이터베이스에 접근하는 메서드는 반환값으로 데이터 객체를 전달한지만, 정해진 것은 아니며 별도의 Dto를 사용하는 경우도 있다.
  • 레포지토리에서 단건 조회를 위한 기본 메서드로 2가지를 제공함.
    • getById() : 내부적으로 EntityManager의 getReference() 메서드를 호출하여 프록시 객체를 반환받는다.
      • 실제 쿼리는 프록시 객체를 통해 최초로 데이터에 접근하는 시점에 실행된다.
      • 이 때, 데이터가 존재하지 않는 경우 EntitiyNotFoundException 발생.
    • findById() : 내부적으로 EntityManager의 find() 메서드 호출.
      • 이 메서드는 영속성 컨텍스트의 캐시에서 값을 조회하며, 값이 존재하지 않은 경우 실제 DB에서 조회한다.
      • 반환값을 Optional 객체 안에 담아서 전달한다.
  • 레포지토리에서 값을 수정 시, update 키워드 대신하여 save() 메서드를 호출한다.
    -
    • 영속성 컨텍스트에서 관리하기 위해서, find() 메서드를 통해 DB에서 값을 가져온 뒤 영속성 컨텍스트가 유지되는 상황에서 객체의 값을 변경하고 다시 save()를 실행하면 JPA에서는 더티 체크를 하여 변경 감지를 수행한다.
    • save() 메서드 내부 구현부를 보면 @Transactional 어노테이션이 선언되어 있는데, 이는 메서드 내 작업을 마치면, 자동으로 flush() 메서드를 실행해준다.

✅DAO 연동을 위한 컨트롤러와 서비스 설계

  • 서버 레이어에서는 도메인 모델을 활용하여 애플리케이션에서 제공하는 핵심 기능을 제공한다.
  • 즉, 서비스 레이어에서는 기능들을 종합해서 핵심 기능을 전달하도록 구성하는 경우가 대표적이다.
  • DAO에서 구현한 기능은 서비스 인터페이스에서 호출하여 결과값을 가져오는 작업을 수행하도록 설계해준다.
  • 각 기능에 대한 요청은 '컨트롤러 - 서비스 - DAO - 레포지토리'의 계층을 따라 이동하고 응답은 요청의 역순으로 전달하는 구조이다.

빌드 메서드

빌더 패턴을 따르는 메서드이다. 데이터 클래스를 사용할 때 생성자로 초기화할 경우 모든 필드에 값을 넣거나 null을 명시적으로 사용해야 함. 이러한 단점을 보완하기 위해 나온 패턴이 빌더 패턴이며, 이 패턴을 아용하면 데이터만 설정이 가능하여 유연성 확보가 가능함.

...
ProductDto(Long num, String name, int price, int stock){
	this.num = num;
    this.name = name;
    this.price = price;
    this.stock = stock;
}
-> 초기화 시, 모든 매개변수에 값을 넣어 초기화 해줘야 함.

...
ProductDto.buider()
	.num(값)
    .name("")
    .price(값)
    .stock(값)
    .build();
이 방식은 초기화가 가능하다.

Lombok(롬복)

  • 롬복은 데이터 클래스를 생성할 때 반복적으로 사용하는 getter/setter와 같은 메서드를 어노테이션으로 대체하는 기능을 제공하는 라이브러리.

장점

  • 어노테이션을 기반으로 코드를 자동 생성하기 때문에 생산성이 높아짐.
  • 반복되는 코드를 생략할 수 있어 가독성이 좋아짐.
  • 롬복을 안다면 간단하게 코드 유추가 가능하여 유지보수에 용이함.

롬복 주요 어노테이션

  • @Getter @Stter: 클래스에 선언되어 있는 필드에 대한 getter/setter 메서드를 생성함.

  • 생성자 자동 어노테이션
    -

    • NoArgsConstructor : 매개변수가 없는 생성자 자동 생성.
    • AllArgsConstructor : 모든 필드를 매개변수로 갖는 생성자 자동 생성.
    • RequiredArgsConstructor : 필드 중 final 또는 @NotNull이 설정된 변수를 매개변수로 갖는 생성자를 자동 생성.
  • @ToString : toString() 메서드 생성하는 어노테이션.

  • @EqualsAndHashCode : 객체의 동등성(equals)과 동일성(hashCode)을 비교하는 연산 메서드를 생성.

동등성과 동일성

동등성은 비교 대상의 두 객체가 가진 값이 같음을 의미하고, 동일성은 두 객체가 같은 객체임을 의미한다.
두 메서드는 일반적으로 클래스 단위의 객체를 비교하는데 사용하고 Object 클래스의 메서드를 오버라이딩하여 구현함.

  • @Data : 위에 설명한 모든 어노테이션을 포괄하는 어노테이션으로, 위에서 언급한 설정을 한번에 생성 가능하다.
profile
백엔드 서버 엔지니어

0개의 댓글