JPA CascadeType 종류

 

1. 배경

- JPA 개인 프로젝트를 진행하던 중, 게시판과 파일, 댓글에서 @OneToMany - @ManyToOne의 관계에서 영속성 관리에서 문제가 발생되었으며, 영속성에서 참조된 객체를 지워주지 않았기 때문에 발생하였다. 더 정확한 내용은 알아볼 예정이다.

 

Entity의 상태

  • Transient : JPA가 모르는 상태 (단순 객체 생성)
  • Persistent : JPA가 관리중인 상태 (1차 캐시, Dirty Checking, Write Behind, ...)
  • Detached : JPA가 더이상 관리하지 않는 상태
  • Removed : JPA가 관리하긴 하지만 삭제하기로 한 상태

 

 2. 내용

  • CascadeType.PERSIST
    엔티티를 영속화 할 때이 필드에 보유 된 엔티티도 유지합니다. EntityManager가 flush 중에 새로운 엔티티를 참조하는 필드를 찾고이 필드가 CascadeType.PERSIST를 사용하지 않으면 오류이므로이 Cascade 규칙의 자유로운 적용을 제안합니다.
  • CascadeType.MERGE
    엔티티 상태를 병합 할 때, 이 필드에 보유 된 엔티티도 병합하십시오.
  • CascadeType.REFRESH
    엔티티를 새로 고칠 때, 이 필드에 보유 된 엔티티도 새로 고칩니다.
  • CascadeType.REMOVE
    엔티티를 삭제할 때, 이 필드에 보유 된 엔티티도 삭제하십시오.
  • CascadeType.DETACH
    부모 엔티티가 detach()를 수행하게 되면, 연관된 엔티티도 detach() 상태가 되어 변경사항이 반영되지 않는다.
  • CascadeType.ALL
    모든 Cascade 적용

즉시 로딩 지연로딩

JPA에서는 데이터를 조회할 때 즉시 로딩(EAGER)과 지연 로딩(LAZY) 두 가지 방식이 있다. 이 두 가지 방식을 간단하게 설명하면 즉시 로딩은 데이터를 조회할 때 연관된 데이터까지 한 번에 불러오는 것이고, 지연 로딩은 필요한 시점에 연관된 데이터를 불러오는 것이라고 할 수 있다.

즉시 로딩(EAGER)

  • @xxToxx(fetch = fetchType.EAGER)

다음과 같이 Member 엔티티와 Team 엔티티가 N:1 매핑으로 관계를 맺고 있다.

 

지연 로딩(LAZY)

  • @xxToxx(fetch = fetchType.LAZY)

아래와 같이 지연 로딩으로 설정하고 Member를 조회해보면 즉시 로딩 방식과 달리 Team을 조회하는 쿼리가 생성되지 않고 Member를 조회하는 쿼리만 나가고, 실제로 팀을 사용하는 시점에 Team을 조회하는 쿼리가 나간다.

'항해 99(9기) > 항해 일일' 카테고리의 다른 글

항해 99 31일차  (0) 2022.10.19
항해 99 30일차  (0) 2022.10.18
항해 99 25일차  (0) 2022.10.13
항해 99 23일차  (0) 2022.10.11
항해 99 20일차  (0) 2022.10.08
  • 기간 10월 07일(금)~10월 13일(목)
  • 스프링 ORM, SQL, MVC

feat…… 카카오 서버실 화재로 인해 서버가 불안정해 계속 사용해오던 티스토리를 사용하지 요번에는 노션으로 작성해봤다……..

ORM 이란?

ORM 이란 Object-Relational Mapping 의 약자로, 이름 그대로 객체(Object)와 관계형 데이터(Relational data) 를 매핑하기 위한 기술이다. 이러한 매핑이 필요한 이유는 객체 지향 언어과 관계형 데이터베이스사이의 패러다임 불일치가 있기때문이다.  이 둘 간의 패러다임 불일치 때문에 개발자는 더 많은 코드를 작성해야 하며, 이는 반복적이고 실수하기 쉬운 작업이 된다. 그렇기 때문에 개발자는 객체지향적인 설계에 집중할 수 없게 된다. ORM이 바로 이러한 문제를 해결해 준다.

https://medium.com/@emccul13/object-relational-mapping-9d84807f5536

🌱 패러다임 불일치

객체 지향 프로그래밍과 관계형 데이터베이스 사이의 데이터 표현 방식이 달라서 생기는 문제를 패러다임 불일치라고 한다. 패러다임 불일치가 일어나는 이유는 애초에 이들의 목표와 동작 방식이 다르기 때문이다.

  • 객체 지향
    • 필드와 메서드 등을 묶어서 객체로 잘 만들어 사용하는 것이 목표
    • 객체 지향 프로그래밍은 추상화, 캡슐화, 정보은닉, 상속, 다형성 등 시스템의 복잡성을 제어할 수 있는 다양한 장치들을 제공한다.
  • 관계형 데이터베이스
    • 데이터를 잘 정규화해서 보관하는 것이 목표

🌱 JPA

JPA는 Java Persistence API의 약자로, 자바 ORM 기술에 대한 API 표준 명세이다. 즉, 인터페이스의 모음이다. 이러한 JPA 인터페이스를 구현한 대표적인 프레임워크가 하이버네이트(Hibernate)이다.JPA는 애플리케이션과 JDBC 사이에서 동작한다. 개발자가 JPA를 사용하면, JPA 내부에서 JDBC API를 사용하여 SQL을 호출하여 DB와 통신한다. 즉, 개발자가 직접 JDBC API를 쓸 필요가 없다.

🌱 Hibernate

JPA를 구현한 프레임워크 중 사실상 표준이다. 오픈소스 소프트웨어이다. 여기서 주목해야할 점은 JPA는 기술 스펙이고 하이버네이트는 이 기능을 구현하여 공급해주는 역할이다.

🌱 Spring Data JPA

Spring framework에서 **JPA를 편리하게 사용할 수 있도록 지원하는 프로젝트(모듈)**이다. Spring Data JPA의 목적은 JPA를 사용할 때 필수적으로 생성해야하나, 예상가능하고 반복적인 코드들을 대신 작성해줘서 코드를 줄여주는 것이다. 이는 JPA를 한 단계 추상화시킨 Repository라는 인터페이스를 제공함으로써 이루어진다.

Spring Data JPA는 JPA Provider이 아니다. 단지 데이터 계층에 접근하기 위해 필요한 뻔한 코드들의 사용을 줄여주도록 하는 인터페이스이다. 여기서 반드시 기억해야할 점은 Spring Data JPA는 항상 하이버네이트와 같은 JPA provider가 필요하다는 것이다.

SQL이란

SQL은 관계형 데이터베이스 관리 시스템(RDBMS)의 데이터를 관리 및 처리하기 위해 설계된 특수 목적의 프로그래밍 언어이며 질의(Query) 언어라고 불리기도 한다. 관계형 데이터 베이스 관리 시스템에서 자료의 검색과 관리, 데이터베이스 스키마 생성과 수정, 데이터 베이스 객체 접근 조정 관리를 위해 고안되었다. MySQL, MariaDB, MSSQL, 오라클 등의 데이터베이스 관련 프로그램들이 SQL을 표준으로 채택하고 있다.

SQL 명령어

  • DDL(Data Definition Language, 데이터 정의 언어)

: DDL은 데이터베이스 스키마와 설명을 처리하도록 정의하는 언어이다. 데이터베이스나 테이블 생성/변경/삭제 등의 작업이 포함된다.

  • CREATE(데이터베이스 개체(테이블, 인덱스, 제약조건 등)의 정의
  • DROP(데이터베이스 개체 삭제)
  • ALTER(데이터베이스 개체 정의 변경)
  • DML(Data Manipulation Language, 데이터 조작 언어)

: 데이터 검색, 삽입, 변경, 삭제 수행을 조작하는 언어이다. 실질적으로 저장된 데이터를 관리하고 처리할 때 사용한다.

  • SELECT(테이블 데이터의 검색 결과 집합의 취득)
  • INSERT(행 데이터 또는 테이블 데이터의 삽입)
  • DELETE(데이터의 삭제)
  • UPDATE(표 업데이트)
  • DCL(Data Control Language, 데이터 제어 언어)

: 사용자 관리 및 사용자별로 릴레이션 또는 데이터를 관리하고 접근하는 권한을 다루기 위한 언어이다.

  • COMMIT : 트랜잭션의 작업 결과를 반영
  • ROLLBACK : 트랜잭션의 작업을 취소 및 원래대로 복구
  • GRANT : 사용자에게 권한 부여
  • REVOKE : 사용자 권한 취소

MVC

소프트웨어 디자인 패턴 중 하나M (Model) / V (view) / C (Controller)

Model : 어플리케이션 정보, 데이터, DB 등 이다.View : 사용자에게 보여지는 화면, UI를 말한다,모델로부터 정보를 얻고 표시한다.Controller : 데이터와 비즈니스 로직사이 상호동작을 관리한다.모델과 뷰를 통제하며, MVC패턴에서 View와 Model이 직접적인 소통을 하지않도록 관리한다.

MVC 1

JSP -> View, Controller 모두 담당하나의 JSP로 유저 요청, 응답 처리 (구현의 난이도는 쉽다)

단순한 작은규모의 프로젝트에는 이 방법이 빠르고 쉽지만,큰 프로젝트에서는 확실히 나눠주는 게 좋다.JSP 하나에서 MVC가 모두 이루어지게되면 재사용성이 떨어지고,읽기도 힘들다. = 유지보수가 힘들다.

그래서 주소요청, 화면구현 따로따로 하기위해 MVC가 나온것이다.

  • 컴포넌트 기반으로 필요한 요소들을 묶어 놓았다!(* 자바를 사용해서 웹을 만들기 위한 기술이 핵심)

컴포넌트

재사용이 가능한 최소단위, 독립적인 소프트웨어 모듈 (교체가능한 부품)컴포넌트는 인터페이스를 통해서만 접근이 가능하다.컴포넌트 내 정보는 외부로부터 모두 숨겨진다. (정보 은닉)

📌 MVC 2

요청을 하나의 컨트롤러(Servlet)가 먼저 받는다.MVC 1과 다르게 역할이 분리되어있으며, M,V,C 중 수정할 부분이 생기면 그것만 꺼내어 수정하면된다. = 유지보수에 있어 장점이 있다.

spring MVC 패턴

스프링에서는 유저의 요청을 받는 DispathcerServlet이 핵심이다.이것이 Front Controller의 역할을 맡는다.Front Controller -> 우선 먼저 유저(클라이언트)의 모든 요청을 받고, 그 요청을 분석하여 세부 컨트롤러들에게 필요한 작업을 나눠주게 된다.

  1. 요청브라우저 특정 URL에 요청을 DispathcerServlet이 받는다.
  2. 요청에 매핑되는 컨트롤러를 검색요청
  • DispathcerServlet이 URI를 보고 controller를 식별하기위해핸들러 매핑과 통신한다.
  • 핸들러 매핑은 요청을 처리하는 특정 핸들러메서드를 반환(return)한다.
  1. 컨트롤러에 처리요청
  • DispathcerServlet은 특정 핸들러 메서드를 호출한다.(public String 특정메서드 (Model model)호출)
  • 핸들러 메서드는 모델과 뷰를 반환(return)한다.(public String 특정메서드 (Model model) {return "view";})
  1. 컨트롤러의 처리결과를 생성할 뷰를 결정한다.
  • DispathcerServlet은 논리적 뷰를 결정하는 뷰 리졸버를 찾아 호출한다. -> 논리적 뷰 이름을 입력한다.
  • 뷰 리졸버는 논리적 뷰 이름 -> 물리적 뷰 이름에 매핑하는 로직을 실행한다. (/template/view.html 으로 변환)
  • 예를들어,return "/hongView"; 를 아래와 같이 변경한다.src/main/resources/template/+return(논리이름)+.html
  • DispathcerServlet은 뷰를 요청해 실행한다.> 뷰에서 model 객체를 사용할 수 있게 한다.
  • DispathcerServlet은 응답을 다시 브라우저로 보낸다.> 결과화면 return

Servlet?

java언어로 웹을 구현하는 기술이며,클라이언트의 요청에 제일 먼저 반응한다.(주소요청을 받고 응답해주는 역할이다.)

ex) 브라우저에서 사용자가 입력하고, 전송하면 다시 결과값을 돌려주는데 여기가 서블릿이라 생각하면된다.

MVC 에서는 model(비즈니스로직), view(화면), controller(주소분기) 중 controller의 역할을 담당한다.

배운것

스프링 부트의 숙련 과정 강의를 보면서 Spring Security 와 JWT의 사용과정을 배웠다.

스프링 부트 공부를 시작하고 처음으로 긴코드(엄청 길지는…)를 다뤄보는 계기가 되었고.

MVC패턴의 구조를 여러가지로 짜보면서 익숙해지는 것 같았다. 그리고 JPA의 연관관계 영속성 등 을 더 알수 있게 되었다.

아쉬운점/느낀점

처음으로 스프링 부트의 SECURITY와 SECURITY의 필터를 중간에서 가로채서 JWT를 적용해 로그인 세션을 사용하지 않는 토큰을 사용하는 방법을 배웠다. 처음에는 그 과정을 이해하려고 노력을 많이 했고 그 과정에서 시간이 많이 들었다. 영상도 찾아보고 많은 문서들을 보면서 JWT를 구현 했지만

많은 부분들이 어렵게 느껴졌다. 웹페이지를 만드는 과정에서 가장 중요시 해야 할 보안 기능과 인증 인가기능 을 구현하면서 보안이 중요하다는 것을 느꼈고. 보안에 대해서 여러가지 찾아보면서 보안의 중요성을 더 알 수 있는 시간이였다.

'항해 99(9기) > WIL' 카테고리의 다른 글

항해 99 (9기) 7주차 WIL  (0) 2022.11.06
항해 (9기) 6주차 WLI 회고  (0) 2022.10.30
항해 99(9기) 3주차 WTL 회고  (0) 2022.10.09
항해 99(9기) 2주차 회고  (0) 2022.10.02
항해 99 (9기) 1주차 회고  (1) 2022.09.25

ORM 이란?

  ORM 이란 Object-Relational Mapping 의 약자로, 이름 그대로 객체(Object)와 관계형 데이터(Relational data) 를 매핑하기 위한 기술이다. 이러한 매핑이 필요한 이유는 객체 지향 언어과 관계형 데이터베이스사이의 패러다임 불일치가 있기때문이다.  이 둘 간의 패러다임 불일치 때문에 개발자는 더 많은 코드를 작성해야 하며, 이는 반복적이고 실수하기 쉬운 작업이 된다. 그렇기 때문에 개발자는 객체지향적인 설계에 집중할 수 없게 된다. ORM이 바로 이러한 문제를 해결해 준다. 

https://medium.com/@emccul13/object-relational-mapping-9d84807f5536

 

🌱 패러다임 불일치

 객체 지향 프로그래밍과 관계형 데이터베이스 사이의 데이터 표현 방식이 달라서 생기는 문제를 패러다임 불일치라고 한다. 패러다임 불일치가 일어나는 이유는 애초에 이들의 목표와 동작 방식이 다르기 때문이다.

  • 객체 지향
    • 필드와 메서드 등을 묶어서 객체로 잘 만들어 사용하는 것이 목표
    • 객체 지향 프로그래밍은 추상화, 캡슐화, 정보은닉, 상속, 다형성 등 시스템의 복잡성을 제어할 수 있는 다양한 장치들을 제공한다.
  • 관계형 데이터베이스
    • 데이터를 잘 정규화해서 보관하는 것이 목표

 

🌱 JPA

  JPA는 Java Persistence API의 약자로, 자바 ORM 기술에 대한 API 표준 명세이다. 즉, 인터페이스의 모음이다. 이러한 JPA 인터페이스를 구현한 대표적인 프레임워크가 하이버네이트(Hibernate)이다.JPA는 애플리케이션과 JDBC 사이에서 동작한다. 개발자가 JPA를 사용하면, JPA 내부에서 JDBC API를 사용하여 SQL을 호출하여 DB와 통신한다. 즉, 개발자가 직접 JDBC API를 쓸 필요가 없다.

 

🌱 Hibernate

 JPA를 구현한 프레임워크 중 사실상 표준이다. 오픈소스 소프트웨어이다. 여기서 주목해야할 점은 JPA 기술 스펙이고 하이버네이트는  기능을 구현하여 공급해주는 역할이다.

 

🌱 Spring Data JPA

 Spring framework에서 JPA를 편리하게 사용할 수 있도록 지원하는 프로젝트(모듈)이다. Spring Data JPA의 목적은 JPA를 사용할 때 필수적으로 생성해야하나, 예상가능하고 반복적인 코드들을 대신 작성해줘서 코드를 줄여주는 것이다. 이는 JPA를 한 단계 추상화시킨 Repository라는 인터페이스를 제공함으로써 이루어진다.

 Spring Data JPA는 JPA Provider이 아니다. 단지 데이터 계층 접근하기 위해 필요한 뻔한 코드들의 사용을 줄여주도록 하는 인터페이스이다. 여기서 반드시 기억해야할 점은 Spring Data JPA 항상 하이버네이트와 같은 JPA provider 필요하다는 것이다.

출처 : 스프링부트와 aws로 혼자 구현하는 웹서비스(이동욱 저)

'항해 99(9기) > 항해 일일' 카테고리의 다른 글

항해 99 30일차  (0) 2022.10.18
항해 99 29일차  (0) 2022.10.17
항해 99 23일차  (0) 2022.10.11
항해 99 20일차  (0) 2022.10.08
항해 99 19일차  (1) 2022.10.07

연관 관계 정의 규칙

연관 관계를 매핑할 때, 생각해야 할 것은 크게 3가지가 있습니다.

  • 방향 : 단방향, 양방향 (객체 참조)
  • 연관 관계의 주인 : 양방향일 때, 연관 관계에서 관리 주체
  • 다중성 : 다대일(N:1), 일대다(1:N), 일대일(1:1), 다대다(N:M)

하나 하나 생각해보겠습니다.

단방향, 양방향

데이터베이스 테이블은 외래 키 하나로 양 쪽 테이블 조인이 가능합니다.

따라서 데이터베이스는 단방향이니 양방향이니 나눌 필요가 없습니다.

그러나 객체는 참조용 필드가 있는 객체만 다른 객체를 참조하는 것이 가능합니다.

그렇기 때문에 두 객체 사이에 하나의 객체만 참조용 필드를 갖고 참조하면 단방향 관계, 두 객체 모두가 각각 참조용 필드를 갖고 참조하면 양방향 관계라고 합니다.

엄밀하게는 양방향 관계↔️는 없고 두 객체가 단방향 참조를 각각 가져서 양방향 관계처럼 사용하고 말하는 것입니다. ⬅️ ➡️

JPA를 사용하여 데이터베이스와 패러다임을 맞추기 위해서 객체는 단방향 연관 관계를 가질지, 양방향 연관 관계를 가질지 선택해야합니다.

선택은 비즈니스 로직에서 두 객체가 참조가 필요한지 여부를 고민해보면 됩니다.

  • Board.getPost()처럼 참조가 필요하면 Board→Post 단방향참조
    • 만약 참조가 굳이 필요없으면 참조를 안하면 됨
  • post.getBoard()처럼 참조가 필요하면 Post→Board 단방향참조
    • 만약 참조가 굳이 필요없으면 참조를 안하면 됨

이렇게 비즈니스 로직에 맞게 선택했는데 두 객체가 서로 단방향 참조를 했다면 양방향 연관 관계가 되는 것입니다.

단방향 연관 관계와 양방향 연관 관계를 구분하는 방법은 이렇게 이해하면 됩니다.

무조건 양방향 관계를 하면 쉽지 않나❓

객체 입장에서 양방향 매핑을 했을 때 오히려 복잡해질 수 있습니다.

예를 들어 일반적인 비즈니스 애플리케이션에서 사용자(User)엔티티는 굉장히 많은 엔티티와 연관 관계를 갖습니다.

이런 경우에 모든 엔티티를 양방향 관계로 설정하게 되면 사용자(User)엔티티는 엄청나게 많은 테이블과 연관 관계를 맺게 되고 User클래스를 보면 엄청나게 복잡해진 것을 확인할 수 있습니다.

그리고 다른 엔티티들도 불필요한 연관관계 매핑으로 인해 복잡성이 증가할 수 있습니다.

그래서 양방향으로 할지 단방향으로 할지 필히 구분해줘야합니다.

구분하기 좋은 기준은 기본적으로 단방향 매핑으로 하고 나중에 역방향으로 객체 탐색이 꼭 필요하다고 느낄 때 추가하는 것으로 잡으면 됩니다.

그냥 참조만 추가한다고 되는 건 아니고 자세한 것은 아래에서 설명합니다.

연관 관계의 주인

두 객체(A, B)가 양방향 관계, 다시 말해 단방향 관계 2개(A→B, B→A)를 맺을 때, 연관 관계의 주인을 지정해야 합니다.

연관 관계의 주인을 지정 하는 것은 두 단방향 관계(A→B, B→A)중, 제어의 권한(외래 키를 비롯한 테이블 레코드를 저장, 수정, 삭제 처리)을 갖는 실질적인 관계가 어떤 것인지 JPA에게 알려준다고 생각하면 됩니다.

 

연관 관계의 주인은 연관 관계를 갖는 두 객체 사이에서 조회, 저장, 수정, 삭제를 할 수 있지만, 연관 관계의 주인이 아니면 조회만 가능합니다.

연관 관계의 주인이 아닌 객체에서 mappedBy 속성을 사용해서 주인을 지정해줘야합니다.

TIP : 외래 키가 있는 곳을 연관 관계의 주인으로 정하면 됩니다. 무조건. 😄

왜 연관 관계의 주인을 지정해야하는가?

두 객체 (Board, Post)가 있고 양방향 연관 관계를 갖는다고 생각해봅니다.

그 상황에서 게시글(Post)의 게시판을 다른 게시판(Board)으로 수정하려고 할 때, Post 객체에서 setBoard(...) 같은 메소드를 이용해서 수정하는게 맞는지, Board객체에서 getPosts() 같은 메소드를 이용해서 List의 게시글을 수정하는게 맞는지 헷갈릴 수 있습니다. 🤔

두 객체 입장에서는 두 방법 다 맞는 방법이긴 합니다.

그러나 이렇게 객체에서 양방향 연관 관계 관리 포인트가 두 개일 때는 테이블과 매핑을 담당하는 JPA입장에서 혼란을 주게 됩니다.

즉, Post에서 Board를 수정할 때 FK(Foreign Key)를 수정할 지, Board에서 Post를 수정할 때 FK(Foreign Key)를 수정할 지를 결정하기 어려운 것입니다.

그렇기 때문에 두 객체 사이의 연관 관계의 주인을 정해서 명확하게 Post에서 Board를 수정할 때만 FK를 수정하겠다! 라고 정하는 것입니다.

연관 관계의 주인만 제어하면 되나?

데이터베이스에 외래 키가 있는 테이블을 수정하려면 연관 관계의 주인만 변경하는 것이 맞는가? 맞습니다.

맞긴 하지만, 그것은 데이터베이스만 생각했을 때고, 객체를 생각해보면 사실 둘 다 변경해주는 것이 좋습니다. (연관 관계의 주인이 아닌 곳에서도 변경!)

왜냐하면 두 참조를 사용하는 순수한 두 객체는 데이터 동기화를 해줘야하기 때문입니다.

 

다중성

데이터베이스를 기준으로 다중성을 결정합니다.

(JPA는 JPQL도 그렇고 보통 객체를 기준으로 하는게 일반적인데 다중성을 정하는 기준은 데이터베이스 기준인게 신기합니다.)

  • 연관 관계는 대칭성을 갖습니다.
    • 일대다 ↔ 다대일
    • 일대일 ↔ 일대일
    • 다대다 ↔ 다대다

다대일(N:1)

게시판(Board)과 게시글(Post)의 관계로 예를 들겠습니다.

  • 요구 사항
    • 하나의 게시판(1)에는 여러 게시글(N)을 작성할 수 있습니다.
    • 하나의 게시글은 하나의 게시판에만 작성할 수 있다.
    • 게시글과 게시판은 다대일 관계를 갖습니다.

데이터베이스를 기준으로 다중성(게시글N : 게시판1)을 결정했습니다.

즉, 외래 키를 게시글(N)이 관리하는 일반적인 형태입니다. (참고로 데이터베이스는 무조건 다(N)쪽이 외래 키를 갖습니다.)

다대일(N:1) 단방향

 

 

일대다(1:N)

어? 일대다는 다대일에서 반대 입장인데 정리할 필요가 있나? 생각할 수 있지만 앞서 다대일의 기준은 연관관계의 주인 다(N)쪽에 둔 것이고 이번에 언급할 일대다의 기준은 연관관계의 주인을 일(1)쪽에 둔 것입니다.

※ 참고로 실무에서는 일대다(1:N) 단방향은 거의 쓰지 않도록 합니다.

일대다(1:N) 단방향

데이터베이스 입장에서는 무조건 다(N)쪽에서 외래키를 관리합니다.

 

@OneToManymappedBy가 없어집니다. 양방향이 아니기 때문입니다.

대신 @JoinColumn을 이용해서 조인을 합니다.

 

다대다(N:N)

  • 실무 사용 금지 ❌
    • 중간 테이블이 숨겨져 있기 때문에 자기도 모르는 복잡한 조인의 쿼리(Query)가 발생하는 경우가 생길 수 있기 때문입니다.
    • 다대다로 자동생성된 중간테이블은 두 객체의 테이블의 외래 키만 저장되기 때문에 문제가 될 확률이 높습니다. JPA를 해보면 중간 테이블에 외래 키 외에 다른 정보가 들어가는 경우가 많기 때문에 다대다를 일대다, 다대일로 풀어서 만드는 것(중간 테이블을 Entity로 만드는 것)이 추후 변경에도 유연하게 대처할 수 있습니다.

출처: https://jeong-pro.tistory.com/231 [기본기를 쌓는 정아마추어 코딩블로그:티스토리]

'항해 99(9기) > 항해 일일' 카테고리의 다른 글

항해 99 29일차  (0) 2022.10.17
항해 99 25일차  (0) 2022.10.13
항해 99 20일차  (0) 2022.10.08
항해 99 19일차  (1) 2022.10.07
항해 99 18일차  (0) 2022.10.06
  • 기간 9월 30일(금)~10월 06일(목)
  • 스프링 기본 문법 및 기본적인 API 설계

 

DI 란?

의존성 주입(Dependency Injection, DI)

  • 설정 파일(XML)이나 어노테이션을 통해 객체 간 의존 관계를 설정하여, 의존하고 있는 객체를 직접 생성하거나 검색할 필요가 없다.
  • 구성요소 간의 의존 관계가 소스코드 내부가 아닌 외부에서 설정을 통해 정의되어 있기 때문에, 코드 재사용을 높여 소스코드를 다양한 곳에 사용할 수 있으며, 모듈간의 결합도도 낮출 수 있다.계층, 서비스 간에 의존성이 존재하는 경우 스프링 프레임워크가 서로 연결시켜준다.
  • 클래스 모델이나 코드에는 런타임 시점의 의존관계가 드러나지 않는다. 그러기 위해서는 인터페이스만 의존하고 있어야 한다.
  • 런타임 시점의 의존관계는 컨테이너나 팩토리 같은 제3의 존재가 결정한다.
  • 의존관계는 사용할 오브젝트에 대한 레퍼런스를 외부에서 제공(주입)해줌으로써 만들어진다.

        - 이일민, 토비의 스프링 3.1, 에이콘(2012), p114

DI 장점!

1. 의존성이 줄어든다.

앞서 설명했듯이, 의존한다는 것은 그 의존대상의 변화에 취약하다는 것이다.(대상이 변화하였을 때, 이에 맞게 수정해야함) DI로 구현하게 되었을 때, 주입받는 대상이 변하더라도 그 구현 자체를 수정할 일이 없거나 줄어들게됨.

2. 재사용성이 높은 코드가 된다.

 있다.

3. 테스트하기 좋은 코드가 된다.

4. 가독성이 높아진다.

 

IOC란?

제어 역전(Inversion of Control, IoC)

  • 기존에는 객체의 의존관계를 개발자가 직접 처리해 주곤 했다. 하지만 스프링에서는 객체 생성과 의존 관계를 자바코드로 직접 처리하는 것이 아니라 컨테이너가 라이프사이클, 클래스 등을 직접 처리한다. 즉, 개발자가 직접 제어하는 부분을 프레임워크가 대신 제어하게 되어 제어권을 가지게 되었다. 그래서 제어의 역전이라고 한다.
  • 스프링에서는  '오브젝트' '빈(Bean)'이라고 칭한다.
  • @Autowired 어노테이션을 사용함으로써 개발자가 직접 의존관계를 설정해주는 코드가 사라지고 프레임워크에 오브젝트 의존관계의 제어권을 맡길 수 있게 된다.

스프링 빈(Spring Bean)이란?

Spring IoC 컨테이너가 관리하는 자바 객체를 빈(Bean)이라고 부른다.

 

빈이란?

  • Bean은 Spring IoC Container가 관리하는 자바 객체, Spring Bean Container에 존재하는 객체를 말한다.
  • Spring IoC(Inversion of Control) Contatiner에 의해 인스턴스화, 관리, 생성된다.
  • Bean Container는 의존성 주입을 통해 Bean 객체를 사용할 수 있도록 해준다.
  • Spring에서 Bean은 보통 Singleton으로 존재한다.
    Singleton : 어떤 Class가 최초 한번만 메모리를 할당하고(Static) 그 메모리에 객체를 만들어 사용하는 디자인 패턴

Bean 생성 방식

Component Scanning

Spring IoC Container가 IoC Container를 만들고 그 안에 Bean을 등록할때 사용하는 Interface들을 Life Cycle Callback이라고 부른다.

Life Cycle Callback 중에는 @Component이 붙어있는 모든 Class의 Instance를 생성해 Bean으로 등록하는 작업을 수행하는 Annotation Processor가 등록 돼있다.
Instance : 일반적으로 실행 중인 임의의 프로세스, 해당 클래스의 구조로 컴퓨터 저장공간에서 할당되어 현재 생성된 Object를 의미.

이때, @ComonentScan Annotation이 붙어있는 Class가 이에 해당한다.

 

즉, @ComponentScan, @Component Anotation을 사용해서 Bean을 등록하는 방법이다.

 

@ComponentScan은 어느 지점부터 Component를 찾으라고 알려주는 역할을 하고,

@Component는 실제로 찾아서 Bean으로 등록할 Class를 의미한다.

 

@ComponentScan @Component이 부여된 Class를 찾아 자동으로 Bean으로 등록해주는 역할을 한다.

@ComponentScan이 붙어있는 Class가 있는 package에서부터 모든 하위 package의 모든 Class를 찾아 다니며,

@Component나 @Component를 사용하는 다른 Annotation을 사용하는 Class를 찾는다.
[EX] Stereotype Annotation(@Controller, @Service, @Repository 등)
Stereotype Annotation들은 내부적으로 @Component Annotation을 사용한다.

Configuration

Configuration을 이용한 Bean 등록 방법은, XML에 설정하는 방법과 Java Class에 설정하는 방법이 있다.
Bean 설정파일은 XML과 자바 설정파일로 작성할 수 있는데 일반적으로는 XML에 설정하지만, 최근 추세는 자바 설정파일을 좀 더 많이 사용한다.

 

@Configuration 사용, @Bean 정의

먼저 Java class에서 @Configuration Annotation을 사용해서 직접 @Bean을 등록해주는 방법이다.
일반적으로 xxxxConfiguration와 같이 명명한다.

@Bean Annotation을 사용해 직접 Bean을 정의하면 자동으로 Bean으로 등록된다.

이렇게 Bean을 직접 정의해서 등록하면 @Component Annotation을 붙이지 않아도 된다.

 

Bean Scope

Spring은 기본적으로 모든 Bean을 Singleton으로 생성하여 관리한다.
Singleton Bean은 Spring Container에서 한 번 생성 후, Container가 사라질 때 Bean도 제거.
생성된 하나의 Instance는 Single Beans Cache에 저장되고, 해당 Bean에 대한 요청과 참조가 있으면 캐시된 객체를 반환.
하나만 생성되기 때문에 동일한 것을 참조, 기본적으로 모든 Bean은 Scope가 명시적으로 지정되지 않으면 Singleton.

구체적으로는 Application 구동 시 JVM 안에서 스프링이 Bean마다 하나의 객체를 생성하는 것을 의미한다.

그래서 Spring을 통해서 Bean을 주입 받으면 언제나 주입받은 Bean은 동일한 객체라는 가정하에서 개발 한다.

 

 

배운 것

전반적인 스프링 부트에대한 기동원리와 거기서 사용하는 언어테이션 등 자바의 기본적인 문법들을 배운 뒤 그것을 활용하는 방법에 익수해지는 시간이였다.

 

아쉬웠던 점/느낀점

처음 배우는 언어인 만큼 여러가지 프레임워크들을 사용해야 했다. JPA를 사용하면서 기존의 사용하던 쿼리문을 사용하지 않아 처음에는 불편한 감이 있었지만 JPA에서 자동으로 쿼리문을 만들어주고 처음에는 이걸 왜 사용하지? 이런 생각을 했지만 조금씩 코드가 복잡해지면서 가독성? 코드 길이 등 처리속도가 빨라지는 것을 느꼈다.

스프링 부트에서 쓰는 어노테이션 아예 새로운 언어로 느껴졌고 그것에 대한 기능들을 알지 못해 사용하은 하지만 이게 왜 되는지는 생각해보지 않고 했었던 것 같다. 기본적인 셋팅과정등 붙여넣기만 하는게 아니라 그거를 실행 시켜보고 이게 왜 작동하는지는 공식 문서 밑 구글링을 하면서 좀 더 자세하게 알아보아야 할 것 같다.

 

'항해 99(9기) > WIL' 카테고리의 다른 글

항해 99 (9기) 7주차 WIL  (0) 2022.11.06
항해 (9기) 6주차 WLI 회고  (0) 2022.10.30
항해 99 주차 4WIL  (0) 2022.10.16
항해 99(9기) 2주차 회고  (0) 2022.10.02
항해 99 (9기) 1주차 회고  (1) 2022.09.25

AOP(관점 지향 프로그래밍)란?

  • 부가기능을 모듈화
    • AOP (Aspect Oriented Programming) 를 통해 부가기능을 모듈화
      • **'부가기능'**은 '핵심기능'과는 관점(Aspect), 관심이 다름
      • 따라서 '핵심기능'과 또옥~!! 분리해서 '부가기능' 중심으로 설계, 구현 가능

  • 스프링이 제공하는 AOP

  1. Aspect: Advice + PointCut
  2. Advice: 어떤 부가기능을 언제?
  3. PointCut: 부가기능 적용 위치. 어느 패키지/메서드에?
부가기능을 핵심기능에서 필요로 할 때만 불러다 실행하고 다시 호출됐던 그 명령을 핵심 기능에 넘겨주는 역활

개념적으로는 수행전 수행후 혹은 두 모두에서 실행되는 매서드로 볼 수 있다.

실제 스프링 내부에서는 AOP 프록시라는 요소에 의해 사용자의 요청을 컨트롤러에 닿기 전 먼저 가로채 필요한 부가기능을 실행한 후에 다시 컨트롤러로 보내준다.

 

  • 스프링 AOP 어노테이션
    1. @Aspect - 스프링 빈 (Bean) 클래스에만 적용 가능
    2. 어드바이스 종류
      • @Around: '핵심기능' 수행 전과 후 (@Before + @After)
      • @Before: '핵심기능' 호출 전 (ex. Client 의 입력값 Validation 수행)
      • @After: '핵심기능' 수행 성공/실패 여부와 상관없이 언제나 동작 (try, catch 의 finally() 처럼 동작)
      • @AfterReturning: '핵심기능' 호출 성공 시 (함수의 Return 값 사용 가능)
      • @AfterThrowing: '핵심기능' 호출 실패 시. 즉, 예외 (Exception) 가 발생한 경우만 동작 (ex. 예외가 발생했을 때 개발자에게 email 이나 SMS 보냄)
    3. 포인트컷
      • 포인트컷 Expression Language
        • 포인트컷 Expression 형태
          • ? 는 생략 가능
        • execution(modifiers-pattern? return-type-pattern declaring-type-pattern? **method-name-pattern(param-pattern)** throws-pattern?)

포인트컷

  • 포인트컷 Expression Language
    • 포인트컷 Expression 형태
      • ? 는 생략 가능
    • execution(modifiers-pattern? return-type-pattern declaring-type-pattern? **method-name-pattern(param-pattern)** throws-pattern?)
    • 포인트컷 Expression 예제
    • @Around("execution(public * com.sparta.springcore.controller..*(..))") public Object execute(ProceedingJoinPoint joinPoint) throws Throwable { ... }
    • modifiers-pattern, 제어자
      • public, private, *
    • return-type-pattern, 반환타입
      • void, String, List<String>, *****
    • declaring-type-pattern, 클래스
      • 클래스명 (패키지명 필요)
      • com.sparta.springcore.controller.* - controller 패키지의 모든 클래스에 적용
      • com.sparta.springcore.controller.. - controller 패키지 및 하위 패키지의 모든 클래스
    • method-name-pattern(param-pattern)
      • 함수명
        • addFolders : addFolders() 함수에만 적용
        • add* : add 로 시작하는 모든 함수에 적용
      • 파라미터 패턴 (param-pattern)
        • (com.sparta.springcore.dto.FolderRequestDto) - FolderRequestDto 인수 (arguments) 만 적용
        • () - 인수 없음
        • (*) - 인수 1개 (타입 상관없음)
        • (..) - 인수 0~N개 (타입 상관없음)
    • @Pointcut
      • 포인트컷 재사용 가능
      • 포인트컷 결합 (combine) 가능

@Component

@Aspect

public class Aspect {

@Pointcut("execution(* com.sparta.springcore.controller.*.*(..))")

private void forAllController() {}

@Pointcut("execution(String com.sparta.springcore.controller.*.*())")

private void forAllViewController() {}

@Around("forAllContorller() && !forAllViewController")

public void saveRestApiLog() { ... }

@Around("forAllContorller()")

public void saveAllApiLog() { ... } }

 

'항해 99(9기) > 항해 일일' 카테고리의 다른 글

항해 99 25일차  (0) 2022.10.13
항해 99 23일차  (0) 2022.10.11
항해 99 19일차  (1) 2022.10.07
항해 99 18일차  (0) 2022.10.06
항해 99 17일차  (0) 2022.10.05

+ Recent posts