TIL 29 [ Spring ( Filter, 객체와 RDB, JPA , 영속성 컨텍스트, Entity 제작 ) ]

2025. 3. 31. 19:53·[내일배움캠프-Sparta]/Spring 6기
반응형

1️⃣ Filter 

✅ 공통 관심사항 ( = 횡단 관심사 )

여러 위치에서 공통적으로 사용되는 부가 기능이고 Filter가 나온이유는 공통 관심사의 처리 때문임.

CRUD는 핵심 기능 ➡ 비즈니스 로직

파란 기능들이 부가기능 ➡ 비즈니스 로직과는 별개로 동작하는 기능 

 

🚀 요구사항 : 로그인 한 유저만 특정 API를 사용할 수 있어야 한다.

  • 해결방법
    • 언제나 핵심은 수정에 있다!
    1. 화면에서 로그인 하지 않으면 API를 사용하지 못하도록 막는다.
      • 유저가 HTTP 요청을 마음대로 조작할 수 있다.
    2. Controller에서 로그인 여부를 체크하는 Logic을 작성한다.
      • 실제로는 인증이 필요한 모든 컨트롤러에 공통으로 로그인 여부를 체크해야 한다.
      • 로그인 로직이 변경될 때 마다 로그인 여부를 체크하는 Logic 또한 변경될 가능성이 높다.
@RestController
@RequestMapping("/post")
public class PostController {

    @PostMapping
    public PostResponseDto create(PostCreateRequestDto request) {
        // 로그인 여부 확인 로직
        // 생성 로직
    }

    @PutMapping("/{postId}")
    public void update(
            @PathVariable Long postId,
            PostUpdateRequestDto request
    ) {
        // 로그인 여부 확인 로직
        // 수정 로직
    }

    @DeleteMapping("/{postId}")
    public void delete(@PathVariable Long postId) {
        // 로그인 여부 확인 로직
        // 삭제 로직
    }

}

위와같이 여러가지 로직에서 공통으로 관심이 있는 부분을 공통 관심사 라고 한다.

➡ Spring AOP를 활용할 수 있다.

➡ Web과 관련된 공통 관심사는 Servlet Filter나 Spring Intercepter를 사용한다.

  • HttpServletRequest 객체를 제공하기 때문에 HTTP 정보나 URL 정보에 접근하기 쉽다.

✅ Servlet Filter

Servlet Filter는 보안, 로깅, 인코딩, 인증/인가 등 다양한 작업을 처리하기 위해 사용

특징

  1. 공통 관심사 로직 처리
    • 공통된 로직을 중앙 집중적으로 구현하여 재사용성이 높고 유지보수가 쉽다.
    • 모든 요청이 하나의 입구를 통해 처리되어 일관성을 유지한다.
  2. HTTP 요청 및 응답 필터링
  3. Filter Chain
    • 여러 개의 필터가 순차적으로 적용될 수 있다.
    • filterChain.doFilter(request, response); 다음 필터로 제어를 전달한다.
  4. doFilter()
    • 실제 필터링 작업을 수행하는 주요 메소드로 필터가 처리할 작업을 정의한다.
    • 다음 필터로 제어를 넘길지 여부를 결정한다.

적용

  • Filter를 적용하면 Servlet이 호출되기 이전에 Filter를 항상 거치게된다.
  • 공통 관심사를 필터에만 적용하면 모든 요청 or 응답에 적용된다 .
  • Filter는 특정 URL Pattern에 적용할 수 있다.
  • Spring을 사용하는 경우 Servlet은 Dispatcher Servlet이다.

Filter Chain

  • Filter는 개발자가 자유롭게 추가할 수 있다.
  • Filter는 순서를 지정하여 추가할 수 있다.
  • Filter는 Chain 형식으로 구성

✅ Filter Interface

Java Servlet에서 HTTP 요청과 응답을 가로채고, 이를 기반으로 다양한 처리 작업을 수행하는 데 사용되는 Interface이다.

⚡ jakarta.servlet.Filter

  • 주요 메서드
  1. init()
    • Filter를 초기화하는 메서드이다.
    • Servlet Container가 생성될 때 호출된다.
    • default method이기 때문에 implements 후 구현하지 않아도 된다.
  2. doFilter()
    • Client에서 요청이 올 때 마다 doFilter() 메서드가 호출된다.
      • doFilter() 내부에 필터 로직(공통 관심사 로직)을 구현하면 된다.
    • WAS에서 doFilter() 를 호출해주고 하나의 필터의 doFilter()가 통과된다면
    • Filter Chain에 따라서 순서대로 doFilter() 를 호출한다.
    • 더이상 doFilter() 를 호출할 Filter가 없으면 Servlet이 호출된다.
  3. destroy()
    • 필터를 종료하는 메서드이다.
    • Servlet Container가 종료될 때 호출된다.
    • default method이기 때문에 implements 후 구현하지 않아도 된다.
@Slf4j
public class CustomFilter implements Filter {
    @Override
    public void doFilter(
            ServletRequest request,
            ServletResponse response,
            FilterChain chain
    ) throws IOException, ServletException {

        // Filter에서 수행할 Logic
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String requestURI = httpRequest.getRequestURI();

        log.info("request URI={}", requestURI);
        // chain 이 없으면 Servlet을 바로 호출
        chain.doFilter(request, response);
    }
}

ServletRequest 는 기능이 별로 없어서 대부분 기능이 많은 HttpServletRequest 를 다운 캐스팅 하여 사용한다.

Filter 등록

@Configuration
public class WebConfig implements WebMvcConfigurer {
		
    @Bean
    public FilterRegistrationBean customFilter() {
            FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<>();
            // Filter 등록
            filterRegistrationBean.setFilter(new CustomFilter());
            // Filter 순서 설정
            filterRegistrationBean.setOrder(1);
            // 전체 URL에 Filter 적용
            filterRegistrationBean.addUrlPatterns("/*");

            return filterRegistrationBean;
    }
}
  • setFilter()
    • 등록할 필터를 파라미터로 전달하면 된다.
  • setOrder()
    • Filter는 Chain 형태로 동작한다.
    • 즉, 실행될 Filter들의 순서가 필요하다.
    • 파라미터로 전달될 숫자에 따라 우선순위가 정해진다.
    • 숫자가 낮을수록 우선순위가 높다.
  • addUrlPatterns()
    • 필터를 적용할 URL 패턴을 지정한다.
    • 여러개 URL 패턴을 한번에 지정할 수 있다.
    • 규칙은 Servlet URL Pattern과 같다.
  • filterRegistrationBean.addUrlPatterns("/*")
    • 모든 Request는 Custom Filter를 항상 지나간다.

2️⃣ 객체와 RDB

✅ 객체와 RDB

📚 객체는 클래스를 통해 만들어지며 속성(field)와 기능(method)를 포함하며 관계형 데이터베이스는 데이터를 테이블 형식으로 표현하며 각 테이블은 열(column)과 행(row)으로 구성된다.

  • 객체 지향 언어 Java
    • 객체를 저장할 수 있는 다양한 종류의 Database
      1. RDB(무결성, 일관성)
      2. NoSQL
      3. File 외기타 등등..
    • 관계형 데이터베이스와 객체 지향의 패러다임 불일치 문제가 발생한다.
  • 관계형 DB에 객체 저장 시 발생하는 문제점
    1. 리소스별 CRUD 반복
    2. 객체의 수정
    3. 패러다임 불일치 문제

✅ 패러다임 불일치 문제 1

객체에서는 상속과 다형성을 통해 객체 관계를 표현할 수 있지만 RDB는 이 개념을 직접 지원하지 않고 별도 매핑이 필요하다. 또한, 객체는 참조로 관계를 표현하고 RDB는 JOIN을 사용하여 관계를 결합한다.

1. 상속

  • DB는 상속관계가 없다.
  • 관계형 DB에서는 Data를 슈퍼타입, 서브타입 관계로 설정한다.

2. 연관관계

테이블의 연관관계는 외래 키를 사용한다

객체의 연관관계는 참조를 사용한다.

public class Tutor {
    private Long id; // PK
    private Company company; // 참조 연관관계
    private String name;

    public Company getCompany() {
            return company;
    }

    public Company setCompany(Company company) {
            this.company = company;
    }
}

public Company {
    private Long id; // PK
    private String name;
}

✅ 패러다임 불일치 문제 2

객체 지향 언어에서 데이터와 동작을 함께 캡슐화하는 방식과, RDB가 데이터를 정규화된 테이블에 관계 중심으로 저장하는 방식의 차이에서 발생한다. 이로 인해 객체를 데이터베이스에 저장하거나 조회할 때 복잡한 매핑과 변환이 필요해지고 코드의 복잡성과 개발자의 부담이 증가한다.

1. 객체 그래프

  • 객체는 연관된 객체를 탐색할 수 있어야 한다.
  • SQL Query
    • 실제로는 실행된 SQL 만큼만 탐색할 수 있다.
    • Entity의 신뢰성에 문제가 발생한다.
    • Layered architecture는 다음 계층을 믿고 사용할 수 있어야한다.
      • Entity는 믿고 사용할 수 있어야한다.
      • productRepository.findById();의 신뢰성 확인이 필요하다.

2. 객체의 비교

Product product1 = productRepository.findById(productId);
Product product2 = productRepository.findById(productId);

product1 == product2; // false
  • 데이터는 같지만, 새로운 인스턴스기 때문에 객체의 주소값이 다르다.

▶  Collection에 저장하면 편하게 사용할 수 있다.

  • 결론
    • 객체 지향적으로 설계하면 코드가 점점 복잡해진다.
      • SQL Query, Mapping이 까다롭다.
    • Collection처럼 객체가 관리된다면 편리해진다.
  • JPA(Java Persistence API) 등장
    • 마치 Java의 Collection처럼 객체를 저장하고 사용할 수 있게 해준다.
    • JPA를 사용하면 패러다임 불일치 문제를 모두 해결할 수 있다.

3️⃣ JPA 

✅ JPA

객체 지향 프로그래밍 언어인 Java와 관계형 데이터베이스 간의 패러다임 불일치 문제를 해결하여 데이터베이스 작업을 객체 지향적으로 수행할 수 있도록 지원한다.

Java의 ORM 기술 표준(인터페이스)

  • 대표적인 구현체로 Hibernate를 주로 사용한다.
  • 표준으로 만들어지면 더욱 명확하게 정의하고 사용할 수 있는 장점이 생긴다.

ORM(Object-Relational Mapping)

ORM은 Java 뿐만이 아니라 다양한 언어에서 존재하는 기술이다.

  • 객체와 관계형 DB를 자동으로 Mapping하여 패러다임 불일치 문제를 해결한다.
  • JDBC API

  • 데이터베이스와 상호작용 하기위해 JDBC API를 개발자가 직접 사용했다.

  • 개발자가 아닌 JPA가 중간에서 개발자의 역할을 대신한다. ( 개발하기 편해짐 )

✅ 사용하는 이유

JPA의 사용 목적은 SQL 중심적인 개발에서 객체 중심으로 개발하기 위함에 있다.

1. 생산성

// 저장 C
jpa.persist(tutor);
// 조회 R
Tutor tutor = jpa.find(Tutor.class, tutorId);
// 수정 U
tutor.setName("수정할 이름");
// 삭제 D
jpa.remove(tutor);
  • persist란 영구히 저장한다는 뜻
  • 마치 컬렉션에 저장한듯 객체가 저장되어 조회가 간편하다.
  • 수정하고자 할 때 꺼낸 객체에 setName() 하면된다.

2. 유지보수성

// 기존
public class Tutor {
    private String id;
    private String name;
}

// 필드 수정
public class Tutor {
    private String id;
    private String name;
    private Integer age;
}
  • 객체 필드가 수정 되어도 SQL은 JPA가 알아서 처리한다.

3. 패러다임 불일치 문제 해결

  • 상속
    • CRUD 방식 다 가능. ( 1. 생산성과 동일 )
  • 연관관계
    • Collection 처럼 사용 할수 있음.
  • 객체 그래프 탐색 
Tutor tutor = jpa.find(Tutor.class, tutorId);
Company company = tutor.getCompany();
  • JPA를 사용하면 신뢰할 수 있는 엔티티, 계층이 된다.
    • JOIN or SQL Query 두번 실행은 JPA로 편하게 할 수 있다.
  • 객체 비교
Tutor tutor1 = jpa.find(Tutor.class, tutorId);
Tutor tutor2 = jpa.find(Tutor.class, tutorId);

tutor1 == tutor2; // true
  • 단, 전제조건으로 동일한 트랜잭션 필수

4. 성능

  • 1차 캐시
    • SQL Query 한번만 실행
Tutor tutor1 = jpa.find(Tutor.class, tutorId); // 실행 결과 1차 캐시에 저장
Tutor tutor2 = jpa.find(Tutor.class, tutorId); // 캐시에서 조회

tutor1 == tutor2; // true
  • 쓰기 지연
    • ORM과 같은 중간 기술이 있으면 한번에 모아서 요청을 보내는것이 가능하다.
    • 네트워크 통신이 한번만 발생하여 비용이 감소된다.
// 트랜잭션 시작
transaction.begin();

jpa.persist(company);
jpa.persist(tutor1);
jpa.persist(tutor2);

// 트랜잭션 제출, JDBC BATCH SQL
transaction.commit();
  • 지연 로딩, 즉시 로딩
    • 지연로딩
      • 필요할 때만 조회하기 때문에 통신 비용 감소
    • 즉시로딩
      • 한번만 조회하기 때문에 네트워크 통신 비용 감소
// 지연 로딩
Tutor tutor = tutorRepository.find(tutorId); // SELECT * FROM tutor
Company company = tutor.getCompany();
String companyName = company.getName(); // SELECT * FROM company

// 즉시 로딩
// SELECT t.*, c.* FROM tutor t JOIN Company c ON
Tutor tutor = tutorRepository.find(tutorId);

Company company = tutor.getCompany();
String companyName = company.getName();

✅ hibernate.dialect

Hibernate가 사용하는 데이터베이스 방언(dialect)을 지정하는 설정으로 데이터베이스와 Hibernate가 상호작용할 때 특정 데이터베이스에 맞게 SQL 구문을 자동으로 조정하는 역할

  • 방언 : SQL 표준을 지키지 않는 특정 데이터베이스 만의 고유한 기능

ex) 페이징

  • MySQL : LIMIT
  • Oracle : ROWNUM
  • JPA는 특정 데이터베이스에 종속되지 않는다.
    • MySQL → Oracle 마음대로 변경이 가능하다.
  • 실무에서 사용되는 DB의 Dialect는 대부분 이미 존재

4️⃣ 영속성 컨텍스트

✅ 영속성 컨텍스트

Entity 객체를 영속성 상태로 관리하는 일종의 캐시 역할을 하는 공간

➡ 여기에 저장된 Entity는 데이터베이스와 자동으로 동기화되며 같은 트랜잭션 내에서는 동일한 객체가 유지

  • 논리적인 개념
    • 눈에 보이지 않는 공간이 생긴다.
  • Entity Manager 를 통해서 영속성 컨텍스트에 접근한다.
    • EntityManager.persist(entity);
  • Entity(객체)를 영속성 컨텍스트에 영속(저장)한다.

✅ Entity

데이터베이스에서 Entity란 저장할 수 있는 데이터의 집합

JPA에서 Entity란 데이터베이스의 테이블을 나타내는 클래스를 의미

Entity 생명주기

  1. 비영속(new/transient)
    • 영속성 컨텍스트가 모르는 새로운 상태
    • 데이터베이스와 전혀 연관이 없는 객체
  2. 영속(managed)
    • 영속성 컨텍스트에 저장되고 관리되고 있는 상태
    • 데이터베이스와 동기화되는 상태
  3. 준영속(detached)
    • 영속성 컨텍스트에 저장되었다가 분리되어 더 이상 기억하지 않는 상태
  4. 삭제(removed)
    • 영속성 컨텍스트에 의해 삭제로 표시된 상태
    • 트랜잭션이 끝나면 데이터베이스에서 제거

➡ 엔티티 상태는 비영속, 영속, 준영속, 삭제 상태로 나뉘며 영속 상태일 때만 JPA의 영속성 컨텍스트가 데이터를 관리

✅ 1차 캐시

엔티티를 영속성 컨텍스트에 저장할 때 생성되는 메모리 내 캐시이다.

➡ 엔티티는 먼저 1차 캐시에 저장되고 이후 같은 엔티티를 요청하면 DB를 조회하지 않고 1차 캐시에서 데이터를 반환하여 성능 ✈

  • Database가 아닌 1차 캐시에 저장된 Entity를 먼저 조회한다.

✅ 동일성 보장

동일한 트랜잭션 안에서 특정 엔티티를 여러 번 조회해도 항상 같은 객체 인스턴스를 반환.

영속성 컨텍스트는 1차 캐시를 사용하여 같은 엔티티를 중복 조회해도 동일한 객체를 참조하게 하여 일관성을 유지함.

  • 동일한 트랜잭션 내에서 조회된 Entity는 같은 인스턴스를 반환한다.
  • DB에 저장된 데이터를 조회하여 1차 캐시에 저장한다.
  • 1차 캐시에 저장된 데이터를 조회한다

✅ 쓰기 지연

엔티티 객체의 변경 사항을 DB에 바로 반영하지 않고 트랜잭션이 커밋될 때 한 번에 반영하는 방식으로 이를 통해 성능을 최적화하고 트랜잭션 내에서의 불필요한 DB 쓰기 작업을 최소화

➡ 동일한 트랜잭션 내에서 생성된 SQL들을 Commit 시점에 한꺼번에 반영한다.

  1. tutor1 1차 캐시에 저장
  2. 쓰기 지연 저장소에 tutor1 INSERT SQL 저장
  3. tutor2 1차 캐시에 저장
  4. 쓰기 지연 저장소에 tutor2 INSERT SQL 저장
  5. flush 되면서 SQL 쿼리 실행  ( DB 반영되기전에 기다림 )
  6. 트랜잭션이 Commit 되면서 실제 DB에 반영

✅ 변경 감지

영속성 컨텍스트가 엔티티의 초기 상태를 저장하고 트랜잭션 커밋 시점에 현재 상태와 비교해 변경 사항이 있는지 확인하는 기능

em.remove() 를 통해 Entity를 삭제할 때도 위와 같은 방식으로 동작한다. DELETE SQL이 트랜잭션 Commit 시점에 실행

✅ flush

영속성 컨텍스트의 변경 내용을 데이터베이스에 반영하는 기능으로, 변경된 엔티티 정보를 SQL로 변환해 데이터베이스에 동기화한다. 트랜잭션 커밋 시 자동으로 실행되지만 특정 시점에 데이터베이스 반영이 필요할 때 수동으로 호출할 수도 있다.

  • flush 사용 방법
    1. 자동 호출
      • 트랜잭션이 Commit 되는 시점에 자동으로 호출된다.
    2. 수동 호출
      • em.flush() 를 통해 수동으로 호출할 수 있다.
    3. 트랜잭션이 Commit되기 전에 SQL이 실행

5️⃣ Entity 제작

✅ @Entity

@Entity가 있다면 JPA가 관리하는 Entity로 만들어진다.

@Entity(name = "Tutor") // 기본 값, name 속성은 생략하면 된다.
@Table(name = "tutor")
public class Tutor {

    // PK
    @Id
    private Long id;

    // 필드
    private String name;

    // 기본 생성자
    public Tutor() {
    }

    // 쉽게 사용하기 위해 생성자 추가
    public Tutor(Long id, String name) {
        this.id = id;
        this.name = name;
    }
}

@Entity

  • JPA를 사용하여 객체를 테이블과 매핑할 때 사용한다.(필수)
  • PK 값이 필수이다.(@Id 사용)
  • 기본 생성자가 필수이다.
  • final, enum, interface, inner 클래스에는 사용 ❌
  • 필드에 final 키워드를 사용 ❌
  • 속성
    • name
      • Entity 이름 지정
      • 기본 값은 클래스 이름과 같다.
      • 혼동을 방지하기 위해 기본 값을 사용(생략)하면 된다.

@Table

  • 속성
    • name
      • Entity와 매핑할 테이블 이름을 지정
      • 기본 값은 Entity 이름(Tutor)을 사용
    • catalog
      • 데이터베이스 catalog 매핑
    • schema
      • 데이터베이스 schema 매핑
    • uniqueConstraints
      • DDL 생성 시 유니크 제약 조건 설정

@Table(name = "tutor") 결과

✅ hibernate.hbm2ddl.auto

JPA는 Application 로딩 시점에 DDL을 자동으로 생성하는 기능을 지원한다. 방언(dialect)을 사용하여 Entity Mapping만 하여도 데이터베이스에 맞는 적절한 DDL이 생성된다.

 

⛔ 자동으로 생성된 DDL은 실제 운영환경이 아닌 개발 환경에서만 사용한다. 필요한 경우에는 자동으로 생성된 DDL을 직접 수정 후 적용

값 설명
create 기존 테이블을 삭제(DROP) 후 다시 생성(CREATE)
create-drop DROP 후 CREATE 하고 종료시점에 테이블을 삭제(DROP), 테스트 시 사용
update 변경된 사항만 DDL에 반영
validate Entity와 테이블이 정상적으로 매핑 되었는지 확인, 실패 시 예외 발생
none 속성을 사용하지 않음
  • application.properties 에서 사용
<property name="hibernate.hbm2ddl.auto" value="create" />
// <property name="hibernate.hbm2ddl.auto" value="create-drop" />
// <property name="hibernate.hbm2ddl.auto" value="update" />
// <property name="hibernate.hbm2ddl.auto" value="validate" />

Validate의 경우

  • Entity와 테이블이 정상적으로 매핑 되었는지 확인, 일치하지 않는다면 PersistenceException

실무에서는 validate 혹은 none 을 사용하고 개발 단계에서는 상황에 맞게 사용하면 된다

✅ 제약조건 설정

JPA를 사용하면 DDL 생성 시 제약조건을 설정할 수 있다. 실행 로직과는 별개로 DDL 생성시에만 활용

➡ DDL을 자동으로 생성할 때만 사용되며 Application 로직에는 영향이 없다.

  • DDL 자동생성 제약조건 설정
    • @Column
      • unique : 유니크, 기본값 false
      • nullable : 필수 여부, 기본값 true ( false면, Not null )
      • length : 길이 ( 문자열만 가능, length=20 이면 VARCHAR(20) )
@Column(unique = true, length = 20, nullable = false)
  • @Table
    • uniqueConstraints : 유니크, 이름을 직접 설정할 수 있다.

✅ 필드 매핑

JPA로 관리되는 클래스인 Entity의 필드는 테이블의 컬럼과 매핑된다.

@Entity
@Table(name = "board")
public class Board {
    @Id
    private Long id;

    // @Column을 사용하지 않아도 자동으로 매핑된다.
    private Integer view;

    // 객체 필드 이름과 DB 이름을 다르게 설정할 수 있다.
    @Column(name = "title")
    private String bigTitle;

    // DB에는 기본적으로 enum이 없다.
    @Enumerated(EnumType.STRING)
    private BoardType boardType;

    // VARCHAR()를 넘어서는 큰 용량의 문자열을 저장할 수 있다.
    @Column(columnDefinition = "longtext")
    private String contents;

    // 날짜 타입 DATE, TIME, TIMESTAMP를 사용할 수 있다.
    @Temporal(TemporalType.TIMESTAMP)
    private Date createdDate;

    @Temporal(TemporalType.TIMESTAMP)
    private Date lastModifiedDate;
    
    @Transient
    private int count;

    public Board() {
    }

}

사용되는 Annotation

종류 설명
@Column DB 컬럼 매핑에 사용
@Temporal 날짜 타입
@Enumerated enum 타입
@Transient DB 컬럼과 매핑하지 않을 때 사용
@Lob tinytext

@Column 속성

속성 설명 Default
name 객체 필드와 매핑할 테이블의 컬럼 이름 객체 필드 이름
nullable DDL 생성 시 null 값의 허용 여부 설정 true(허용)
unique DDL 생성 시 하나의 컬럼에 유니크 제약조건을 설정  
columnDefinition DDL 생성 시 데이터베이스 컬럼 정보를 직접 설정할 수 있다.  
length DDL 생성 시 문자 길이 제약조건 설정 단, String만 사용 가능 255
insertable 설정된 컬럼의 INSERT 가능 여부 true
updatable 설정된 컬럼의 UPDATE 가능 여부 true

@Enumerated

속성 값 설명 Default
value EnumType.ORDINAL ( 잘 사용 ❌ )
EnumType.STRING
enum 순서 저장
enum 이름 저장
EnumType.ORDINAL

@Temporal

속성 값 설명 Default
value TemporalType.DATE
TemporalType.TIME
TemporalType.TIMESTAMP
DATE
TIME
TIMESTAMP
2025-01-01
12:00:00
2025-01-01 12:00:00
  • MySQL에서 TIMESTAMP는 DATETIME 이다.

📣최신 버전의 Hibernate에서 LocalDate, LocalDateTime는 @Temporal이 생략이 가능하다.

 

✅ 기본 키 (PK)

JPA Entity를 생성할 때 기본키는 필수로 생성

 

@Id

  • 수동 생성
Tutor tutor = new Tutor(1L, "wonuk");

@GeneratedValue

  • 자동 생성
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

⚡ PK 생성 전략

  • 영속성 컨텍스트는 PK가 필수이다.
    • 가장 권장되는 방식은 Long Type의 기본 키를 사용하는 것
  • strategy 속성
    • GenerationType
      1. IDENTITY : MySQL, PostgreSQL에서 사용, 데이터베이스가 PK 자동 생성
      2. SEQUENCE : Oracle에서 사용, @SequenceGenerator 와 함께 사용
      3. TABLE : 키 생성용 테이블을 사용, @TableGenerator 와 함께 사용
      4. AUTO : dialect에 따라 자동 지정, 기본값
        • MySQL이면 IDENTITY, Oracle이면 SEQUENCE 로 설정

6️⃣ 연관관계 Mapping

✅ 단방향

객체 간의 관계가 한쪽에서만 참조될 수 있는 관계.

➡ 설정이 단순하고 유지 관리가 쉬우며 불필요한 데이터 접근을 방지할 수 있다.

[1] DB 중심

  • FK 값은 Tutor가 가지고 있다.
    • Tutor만 참조할 수 있다.
    • N:1, 다대일 연관관계, 가장 많이 사용된다.
    • 여러명(N)의 Tutor가 어떤 Company(1)에 소속 되어있는지 설정할 수 있다.

[2] 객체 지향

  • 객체는 다른 객체를 참조한다.
  • N:1 관계는 @ManyToOne, @JoinColumn을 사용한다.
@Entity
@Table(name = "tutor")
public class Tutor {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    // N:1 단방향 연관관계 설정
    @ManyToOne
    @JoinColumn(name = "company_id")
    private Company company;

    // 기본 생성자, getter/setter
}

⭐ Tutor의 FK와 Company의 PK를 @JoinColumn으로 매핑한다.

✅ 양방향

객체 간의 관계가 양쪽에서 서로를 참조할 수 있는 관계

➡ 양쪽에서 데이터를 쉽게 접근할 수 있지만 관계를 관리할 때 한쪽에서만 연관관계를 설정하거나 삭제하지 않도록 주의가 필요

 

테이블에는 변화가 ❌

 

객체 지향

@Entity
@Table(name = "tutor")
public class Tutor {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    // N:1 단방향 연관관계 설정
    @ManyToOne
    @JoinColumn(name = "company_id")
    private Company company;

    // 기본 생성자, getter/setter
}
@Entity
@Table(name = "company")
public class Company {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    // null을 방지하기 위해 ArrayList로 초기화 한다.(관례)
    @OneToMany(mappedBy = "company")
    private List<Tutor> tutors = new ArrayList<>();

    // 기본 생성자, getter/setter
}

 

  • 양방향 연관관계 설정을 위해 mappedBy 속성을 설정한다.
    • Tutor의 company 필드와 매핑된다.
  • 반대 방향으로 객체 그래프를 탐색할 수 있다.

✅ 양방향 연관관계의 주인

mappedBy는 JPA 양방향 연관관계 설정 시 사용되는 속성으로 두 엔티티 간의 관계에서 연관관계의 주인이 아닌 쪽에 선언한다. 이를 통해 외래 키 관리 책임을 주인 엔티티에 두고 매핑이 중복되지 않도록 한다.

 

  1. 두개의 Entity 중 하나를 연관관계의 주인으로 설정 해야한다.
  2. 연관관계의 주인은 mappedBy 속성을 사용하지 않는다.
  3. 연관관계의 주인이 아니라면 mappedBy 속성을 사용한다.
  4. 연관관계의 주인이 아니라면 조회만 가능하다.
  5. 연관관계의 주인만 외래 키를 관리(등록, 수정)할 수 있다.
  • 연관관계의 주인 선정 기준
    • 항상 FK가 있는 곳을 연관관계의 주인으로 지정한다.
    • Company가 주인인 경우
      • Company를 수정할 때 Tutor를 Update하는 SQL이 실행
      • 두번의 SQL이 실행되어야 한다. 혼동되기 쉽다.

👀 새롭게 알게된것 

https://jwt.io/ 사이트 에서 쿠키의 Token 내용을 JSON 형태로 디코딩 해서 정보를 알아볼수  있게 할수 있다.

반응형

'[내일배움캠프-Sparta] > Spring 6기' 카테고리의 다른 글

TIL 31 [ Spring 일정관리 앱 Lv0 ~ 1, + 미니세션 ( 예외처리 ) ]  (0) 2025.04.02
TIL 30 [ Spring ( Data JPA ), 스탠다드반 ( Optional ) ]  (0) 2025.04.01
Spring ( Session, Token, JWT )  (0) 2025.03.30
TIL 28 [ Spring ( Bean Validation, Cookie ) ]  (0) 2025.03.28
TIL 27 [ Spring ( SOLID 객체지향, Container와 Bean, 싱글톤 ) + 스탠다드반 (DI / IOC) ]  (0) 2025.03.27
'[내일배움캠프-Sparta]/Spring 6기' 카테고리의 다른 글
  • TIL 31 [ Spring 일정관리 앱 Lv0 ~ 1, + 미니세션 ( 예외처리 ) ]
  • TIL 30 [ Spring ( Data JPA ), 스탠다드반 ( Optional ) ]
  • Spring ( Session, Token, JWT )
  • TIL 28 [ Spring ( Bean Validation, Cookie ) ]
dimenshun
dimenshun
한 소년의 개발 일기
    반응형
  • dimenshun
    Dev Life Notes
    dimenshun
  • 전체
    오늘
    어제
    • 분류 전체보기 (268)
      • CS (23)
        • 자료구조 (0)
        • 알고리즘 (0)
        • 컴퓨터 구조 (8)
        • 네트워크 (6)
        • 운영체제 (3)
        • DB ( + SQLD ) (5)
        • SW공학 (1)
      • 프로그래밍 (3)
        • Java (0)
        • Spring (0)
        • HTML,CSS (3)
        • JavaScript (0)
      • 개발 툴 (7)
        • Git(버전관리) (1)
        • Docker (3)
        • AWS (2)
        • JSP (1)
      • 코딩테스트(Algorithm) (125)
        • 백준 (6)
        • 프로그래머스 (119)
      • [내일배움캠프-Sparta] (110)
        • Spring 6기 (106)
        • KPT 회고 (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    백엔드
    Til
    CPU
    Python
    It
    Testcode
    운영체제
    코딩테스트
    network
    SQLD
    db
    알고리즘
    메모리
    네트워크
    배포
    SQL
    Java
    spring
    트랜잭션
    web
    AWS
    docker
    OS
    세션
    KPT
    내일배움캠프
    cs
    웹
    개발자
    컴퓨터구조
  • hELLO· Designed By정상우.v4.10.3
dimenshun
TIL 29 [ Spring ( Filter, 객체와 RDB, JPA , 영속성 컨텍스트, Entity 제작 ) ]
상단으로

티스토리툴바