[스프링 JPA] 섹션1~6

haeyoon·2024년 10월 23일
0

섹션2

spring initializer로 파일 생성 (https://start.spring.io/)

dependencies

Spring boot starter Web

웹 요청을 처리하기 위해 사용

spring-boot-starter-json

JSON 파싱(JSON↔Java 객체) 및 생성에 사용되는 오픈소스 라이브러리

  • 직렬화: Jackson을 사용해 Java→JSON
  • 병렬화: Jackson을 사용해 JSON→Java

spring-boot-starter-tomcat

웹 애플리케이션을 빠르게 개발하고 배포할 수 있도록 하는 내장형 서버 / Java 서블릿 컨테이너

Java의 실행 환경인 Java Servlet, JavaServer Pages (JSP), Java Expression Language, Java WebSocket 등을 제공

spring-web-mvc

MVC 기능을 처리

서블릿 API 기반 프레임워크 - DispatcherServelt을 통해 HTTP요청을 받아 적절한 컨트롤러로 매핑

  • model: View에 데이터 전달
  • view: ViewResolver 객체를 통해 컨트롤러가 반환한 값으로 뷰 템플릿 찾아 최종적으로 클라이언트에게 반환될 응답 렌더링
  • controller: 사용자의 요청을 처리하고 적절한 응답을 반환
    • 메서드에 @RequestMapping @GetMapping @PostMapping 사용

Thymeleaf

컨트롤러가 전달하는 데이터를 이용해 동적으로 화면을 만들어주는 역할을 하는 뷰 템플릿 엔진

순수 HTML 구조를 유지

spring data JPA

스프링 부트용 Spring Data Jpa 추상화 라이브러리

스프링 부트 버전에 맞춰 자동으로 JPA 관련 라이브러리 버전을 관리한다

H2 Database

자바로 작성된 관계형 데이터베이스 관리 시스템
따로 설치가 필요없어 개발단계나 테스트 코드에서 자주 활용

Lombok

Java의 라이브러리로 반복되는 메서드를 Anntation을 사용해 자동으로 작성
Getter, Setter, 생성자 등의 코드를 작성

devtools

개발에 편리한 도구를 제공
브라우저에 보여주는 내용은 수정 시 자동으로 재시작해주어 브라우저에 업데이트

섹션3

연관관계

연관관계 주인

양방향 관계일 때 외래키를 가지고 값을 변경하는 권한을 가지는 것

주인이 아닌 객체는 조회(SELECT)만 수행

외래키 선정 기준

  • 일대다 관계에서는 “다” 쪽이 외래키(FK)를 가지고 있다

FK 는 orders의 member_id에만 있음

member의 order 값을 바꾸고 싶으면 fk의 값을 바꿔야함

Q. 둘중에 어느 값을 변경해야 테이블에 변경사항이 반영되는지?

A. 변경 포인트가 두개인 객체는 테이블은 하나(FK)만 변경하면 된다

둘 중에 하나를 연관관계 주인으로 지정하면되고( fk가 가까운곳), ordert 테이블에 FK가 있으니까 order의 member로 연관관계 주인 잡으면 된다

order의 member(FK)를 바꾸면 내 테이블에 있는 컬럼 값 업데이트 된다

  • 일대일관계에서는 FK를 더 많이 조회하는 곳으로 선정한다

코드

package jpabook.jpashop.domain;

import jakarta.persistence.Embeddable;
import lombok.Getter;

@Embeddable 
@Getter 
public class Address {

    private String city;
    private String street;
    private String zipcode;

    ...
    }
}

delivery > Address > city, street, zipcode 의 여러개 칼럼으로 나누어져 있음

= 객체 지향적이지 않고 응집력을 떨어트린다!

@Embeddable

값 타입을 정의하는 곳에 표시

  • 임베디드 타입을 적용하려면
    • 새로운 Class(Address)를 만들고
    • 해당 클래스에 임베디드 타입으로 묶으려던 Attribute들을 넣어준 뒤
    • @Embeddable

→ 주소의 관련된 속성들이 하나의 타입으로 바뀌어 사용

= 객체 지향적이고 응집력 증가!

  • @Embedded

    값 타입을 사용하는 곳에 표시

    public class Delivery {
        @Embedded // 내장 타입
        private Address address;
    }
package jpabook.jpashop.domain;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.List;

@Entity
@Getter @Setter
public class Member {
    @Id @GeneratedValue //pk지정
    @Column(name = "member_id") 
    private Long id;

    private String name;

    @Embedded //내장타입이다, 둘중에 하나만 써도 됨
    private Address address;

    @OneToMany(mappedBy = "member") 
    private List<Order> order = new ArrayList<>();
}

@Entity

JPA가 관리해 DB테이블에 대응하는 하나의 클래스

@GeneratedValue

JPA에서 엔티티 클래스의 주요 키(Primary Key) 값을 자동으로 생성하기 위해 사용되는 어노테이션

  • @Id: JPA로 테이블과 엔티티를 매핑할 때, 식별자로 사용할 필드 위에 붙여 테이블의 Primary Key와 연결

    → 식별자로 사용될 값을 일일히 수동으로 넣어줘야 하는 불편함 해결
  • (strategy = GenerationType. _ )

    • AUTO(기본) / IDENTITY / SEQUENCE / TABLE

@OneToMany(mappedBy = "member")

private List<Order> order = new ArrayList<>();

💡

Q. 두 코드의 차이점?

List<String> list = new ArrayList<>();
ArrayList<String> list = new ArrayList<>();

A.

package jpabook.jpashop.domain;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Entity
@Table(name = "orders")
@Getter @Setter
public class Order {

    @Id @GeneratedValue
    @Column(name = "order_id")
    private Long id;

    @ManyToOne
    @JoinColumn(name = "member_id") //fk이름
    private Member member; //연관관계 주인은 가만히 두면 됨

    @OneToMany(mappedBy = "order")
    private List<OrderItem> orderItems = new ArrayList<>();

    @OneToOne
    @JoinColumn(name = "delivery_id")
    private Delivery delivery;
		
		...
}
@ManyToOne (다대일)@OneToMany (일대다)
@JoinColumn(name = "member_id") // name = FK이름(mappedBy = "member") //연관관계 주인 X
private Member member; //연관관계 주인private List<Order> order = new ArrayList<>();
Order - memberMember - order

@Enumerated(EnumType.*STRING*)

엔티티 매핑에서 Enum타입을 사용할 때 사용

  • EnumType.ORDINAL: enum 순서 값을 DB에 저장
  • EnumType.STRING: enum 이름을 DB에 저장

numType.STRING 으로 할 것!

→ 요구사항이 변경되는 경우 칼럼 값이 중복되는 등 오류가 발생하기 때문

섹션4

  • Controller

사용자의 요청을 처리 한 후 지정된 View에 Model 객체를 전송(MVC패턴의 C)

  • Service

Repository에서 받은 데이터들을 가공하여 Controller에 전송

리포지토리를 이용해 CRUD를 구현

  • Repository

DB에 직접 접근해 도메인 객체를 저장하고 관리하는 저장소

  • Domain

엔티티 선언 (@Entity)을 통해 DB에 저장되는 객체 구현

DB 테이블의 각 Column이 하나의 도메인

섹션5

회원 도메인 개발

  • 회원 리포지토리 개발
  • 회원 서비스 개발
  • 회원 기능 테스트

코드

package jpabook.jpashop.domain.repository;

import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jpabook.jpashop.domain.Member;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public class MemberRepository {

    @PersistenceContext //jpa
    private EntityManager em; // spring이 entitymanager을만들어서 저장

    public void save(Member member){
        em.persist(member);
    }

    public Member findOne(Long id){//단건 조회
        return em.find(Member.class, id);  //타입, pk
    }
    public List<Member> findAll() {//리스트 조회
        return em.createQuery("select m from Member m", Member.class) //jpql??
                .getResultList();
    }

    public List<Member> findByName(String name){
        return em.createQuery("Select m from Member m where m.name=:name", Member.class)
                .setParameter("name", name)
                .getResultList();
    }
}

@PersistenceContext

EntityManager를 빈으로 주입할 때 사용하는 어노테이션

private EntityManager em;

EntityManager: 엔티티를 저장하는 메모리상의 데이터베이스

JPA에서 엔티티를 조작(저장, 수정, 삭제, 조회 등)하고 데이터베이스와의 통신을 수행

💡

@PersistenceContext를 사용해서 EntityManager를 주입받으면?

스프링에서 EntityManager를 Proxy로 감싼 EntityManager를 생성해서 주입해주기에 Thread-Safe를 보장

package jpabook.jpashop.domain.service;

import jpabook.jpashop.domain.Member;
import jpabook.jpashop.domain.repository.MemberRepository;
import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor //final에 있는 필드만 가지고 생성자를 만들어준다
public class MemberService {

    private final MemberRepository memberRepository;

    //기능1. 회원 가입
    @Transactional
    public Long join(Member member){
        validateDuplicateMember(member);//중복 금지
        memberRepository.save(member);
        return member.getId();
    }

    private void validateDuplicateMember(Member member) {
        //EXCEPTION
        List<Member> findMembers = memberRepository.findByName(member.getName()); //조회되면 안됨
        if (!findMembers.isEmpty()){
            throw new IllegalStateException("이미 존재하는 회원입니다.");
        }
    }

    //기능2. 회원 전체 조회
    //@Transactional(readOnly = true)
    public List<Member> findMembers() {
        return memberRepository.findAll();
    }
    //하나 조회
    //@Transactional(readOnly = true)
    public Member findOne(Long memberId){
        return memberRepository.findOne(memberId);
    }

}

기존 코드

@Autowired
private MemberRepository memberRepository;

@Autowired

스프링이 스프링빈에 등록되어있는 멤버리포지토리를 인젝션해준다

단점: test할때 바꿔야할수도 있는데 못바꾼다

@AllArgsConstructor

3째줄 이하 코드와 대체 가능

private final MemberRepository memberRepository;

@Autowired // 생략가능
public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
}

생성자 injection이란?

@RequiredArgsConstructor

final에 있는 필드만 가지고 생성자를 만들어준다

@Transactional

한가지 일을 하는 일련의 코드들을 한 단위로 묶어서 작업을 처리하는 방법

Transaction이란?

(readOnly = true): 조회하는곳에서는 성능을 최적화한다

  • 기능2는 모두 조회하는 기능이므로 가장 위에 readOnly임을 명시하고, 기능1에만 @Transactional을 적어준다

섹션6

상품 도메인 개발

  • 상품 엔티티 개발
  • 상품 리포지토리 개발
  • 상품 서비스 개발

em.persist(item)

Detached 상태(한번이라도 영속화 되었지만 지금은X)의 Entity를 다시 영속화

em.merge(item)

최초 생성된 Entity를 영속화

https://seungh1024.tistory.com/77#google_vignette

+Entity를 영속화 = 영속성 컨텍스트에 저장한다

profile
https://haeyoon12.tistory.com/

0개의 댓글

관련 채용 정보