JPA (Java Persistence API) 기초

붉을 혁 ,참 진·2024년 2월 5일
0

Spring MVC 기초

목록 보기
1/1
post-thumbnail

정의


JAP는 자바 진영에서 객체관계 매핑 (ORM)을 위한 API (인터페이스 모음)이자 Java Persistence Framework (자바 영속성 프레임워크)중 하나로, 데이터베이스와 자바 객체 간의 매핑을 편리하게 처리하는 기술이다. JAP를 사용하면 개발자는 SQL 쿼리를 직접 작성하지 않고도 객체 지향적인 방식으로 데이터를 다룰 수 있다. JAP는 대표적으로 Hibernate, EclipseLink와 같은 구현체를 사용하여 데이터베이스와 상호 작용한다. MyBatis또한 자바 영속성 프레임워크에 속하지만, JPA는 조금 더 객체지향적인 반면, MyBatis는 SQL에 대한 유연성이 더 높다.

  • 이때 매핑(mapping)이란?
    → 이때 매핑이란 두 가지 다른 도메인 또는 시스템 간에 대응되는 부분을 지정하거나 연결하는 과정을 나타낸다.

    → 자바 진영에서 ORM기술 중 하나인 JPA는 데이터베이스의 테이블과 자바 언어의 객체간의 매핑을 제공한다. 이는 객체와 관계형 데이터베이스 간에 존재하는 구조적 차이를 극복하기 위한 기술이다.

    → 간단하게 설명하면, 매핑은 객체의 필드(속성)을 데이터베이스의 테이블 열 (Column)에, 객체 간의 연관성을 데이터베이스의 관계로 매칭시키는 작업을 말한다. 이를 통해 객체 지향적인 코드를 유지하면서도 데이터베이스에 데이터를 저장하고 조회할 수 있다.

    ex) JPA에서는 엔티티 클래스의 필드를 데이터베이스 테이블 열에 매핑하고, 객체 간의 관계를 테이블 간의 외래 키 (Foreign Key)로 매핑하는 작업이 이루어진다.

    ⇒ 요약: 여기서 매핑이란 DB와 객체 사이 정보가 오갈 수 있게 조정해주는 역할

  • 이때 도메인(domain)이란?
    → 도메인은 일반적으로 특정 주제나 범위를 나타낸다.

    → 개발자의 영역에선 도메인은 소프트웨어에서 특정 문제 영역이나 비지니스 영역을 가르킨다. 소프트웨어 개발자들은 특정 도메인의 문제를 해결하고자 하는데, 이때 해당 도메인의 규칙, 용어, 개념들을 이해하고 구현해야 한다.

    - Domain Model: 도메인 모델은 특정 비지니스 도메인 구조와 규칙을 나타내는 추상화된 모델을 의미한다. 이는 해당 도메인에서 발생하는 주요 Entity, Aggregate, Value Object등을 포함한다.

    1. Entity: 식별 가능한 개체로, 시스템에서 추적하고 관리해야하는 중요한 개념이다. 예를 들어 온라인 상점에서 ‘상품 (Product)’나 ‘주문(Order)’이 Entity가 될 수 있다.

    2. Aggregate: 연관된 Entity들의 그룹으로, 특정 규칙에 따라 하나의 루트 Entity를 중심으로 관리된다. Aggregate는 도메인 모델을 단순화 하고 복잡성을 관리하는데 도움이 된다.

    3. Value Object: 값 자체가 중요한 개념으로, 식별자 대신 속성들의 조합으로 구성된다. 예를 들어 좌표나 날짜 범위가 Value Object가 될 수 있다.
    4. Domain Service: 특정 도메인 로직을 수행하는 서비스로, Entity나 Aggregate에서 제공하기 어려운 특수한 기능을 처리한다.

    5. Domain Event: 도메인에서 중요한 사건을 나태나는 이벤트로, 시스템 내부에서 상태 변경을 통지하거나 외부 시스템과의 통합에 사용된다.


주요 특징 및 개념


  1. 객체-관계 매핑: JPA는 자바 객체와 데이터베이스 테이블 간의 매핑을 지원한다. 즉, 자바 객체를 데이터베이스 레코드로 자동으로 변환해주는 ORM 기능을 제공한다.
  2. Entity: JPA에서는 데이터베이스의 테이블을 나타내는 Entity를 정의한다. 각 엔터티는 자바 클래스로 표현되며, 이 클래스의 인스턴스는 데이터 베이스 레코드에 매핑된다.
  3. Entity Manager: JPA는 Entity 객체를 관리하는데 사용되는 Entity Manager을 제공한다. Entity Manager을 통해 데이터베이스에 대한 CRUD연산을 수행할 수 있다.
  4. JPAL (Java Persistence Query Language): SQL과 유사한 JPAL을 사용하여 데이터베이스에 대한 쿼리를 작성할 수 있다. 하지만 JPQL은 테이블이 아닌 Entity 객체에 기반하므로 객체 지향적인 쿼리 작성이 가능하다.
  5. Transaction: JAP는 트랜잭션을 관리하여 데이터베이스 연산의 일관성을 보장한다. 트랜잭션을 시작하고 커밋 또는 롤백을 수행할 수 있다.


ORM (Object-Relational Mapping)

정의


객체와 관계형 데이터 베이스 간의 매핑을 의미한다. 이는 객체 지향 프로그래밍 언어에서 사용되는 객체와 데이터베이스 테이블 사이의 관계를 매핑하는 기술이다. ORM을 사용하면 데이터베이스에서 직접 SQL 쿼리를 작성하는 대신, 객체 지향 프로그래밍 언어에서 제공하는 메서드와 속성을 사용하여 데이터베이스를 다룰 수 있다. 이를 통해 개발자는 데이터베이스와의 상호 작용을 더 추상화하고, 코드를 더 간결하게 작성할 수 있다.

특징


개발 생산성을 향상시키고 코드의 유지보수성을 높일 수 있다. ORM 프레임워크를 사용하면 데이터베이스와의 상호 작용을 추상화하여 더 효율적으로 코드를 작성하고 유지보수 할 수 있다.

종류


  1. Hibernate: Java 언어를 기반으로 하는 ORM 프레임워크로, Java 객체와 관계형 데이터베이스 간의 매핑을 제공한다.
  2. Entity Framework: .NET 프레임워크의 일부로, C# 등의 언어를 사용하는 애플리케이션에서 관계형 데이터 베이스와의 상호 작용을 단순화하는 ORM 프레임워크이다.
  3. Django ORM: Python 웹 프레임워크인 Django에서 제공되는 ORM으로, Python 언어로 개발된 웹 애플리케이션에서 데이터 베이스를 다루는 데 사용된다.


Entity

정의


JPA에서 데이터베이스의 테이블과 매핑되는 자바 객체를 나타낸다.

예시코드 1


import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Person {
    @Id
    private Long id; // Person 테이블의 기본키
    private String name;
    private int age;

    // 기본 생성자, 게터/세터 등 필요한 메서드 작성
}
  • @Entity 어노테이션은 이 클래스가 JPA Entity임을 나타낸다
  • @Id 어노테이션은 해당 필드가 데이터베이스의 기본키 (primary key)에 매핑되는 것을 나타낸다.

예시코드 2


package com.example.domain;

import com.example.controller.request.CommentRequest;
import com.example.controller.request.PostRequest;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;

import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Entity
@Setter
@NoArgsConstructor
@Getter
public class Post {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name="title", columnDefinition = "varchar(20)", nullable = false)
    private String title;
    @Column(name="content", columnDefinition = "text", nullable = false)
    private String content;
    @Column(name="is_anonymous", columnDefinition = "boolean", nullable = false)
    private Boolean isAnonymous = true;
    @CreationTimestamp
    @Column(name = "created_date", columnDefinition = "TIMESTAMP")
    private LocalDateTime createdDate;
    @UpdateTimestamp
    @Column(name = "last_modified_date", columnDefinition = "TIMESTAMP")
    private LocalDateTime lastModifiedDate;

    @OneToMany(mappedBy = "post", fetch = FetchType.EAGER)
    private List<Comment> commentList=new ArrayList<>();
    public static Post from(PostRequest postRequest) {
        Post post = new Post();
        post.setTitle(postRequest.getTitle());
        post.setContent(postRequest.getContent());

        // 명시적으로 isAnonymous 값을 설정하며, null일 경우 기본값인 false로 설정합니다.
        post.setIsAnonymous(postRequest.getIsAnonymous() != null ? postRequest.getIsAnonymous() : false);

        return post;
    }

    public Comment addComment(CommentRequest commentRequest) {
        Comment comment = new Comment();
        comment.setContent(commentRequest.getContent());
        comment.setIsAnonymous(commentRequest.getIsAnonymous());
        comment.setPost(this);
        return comment;
    }
}
  1. Entity 어노테이션 및 클래스 선언
@Entity
@Setter
@NoArgsConstructor
@Getter
public class Post {
    // 클래스 내용
}
  • @Setter, @NoArgsConstructor, @Getter: Lombok 어노테이션으로 Getter, Setter, 기본생성자를 자동으로 생성한다.
  1. 필드 정의
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name="title", columnDefinition = "varchar(20)", nullable = false)
private String title;
@Column(name="content", columnDefinition = "text", nullable = false)
private String content;
@Column(name="is_anonymous", columnDefinition = "boolean", nullable = false)
private Boolean isAnonymous = true;
@CreationTimestamp
@Column(name = "created_date", columnDefinition = "TIMESTAMP")
private LocalDateTime createdDate;
@UpdateTimestamp
@Column(name = "last_modified_date", columnDefinition = "TIMESTAMP")
private LocalDateTime lastModifiedDate;
  • @Id: 기본키를 나타낸다.
  • @GeneratedValue: 기본키의 자동 생성 전략을 지정한다.
  • @Column: 데이터베이스 컬럼에 대한 매핑 정보를 제공한다.
  1. OneToMany 관계
@OneToMany(mappedBy = "post", fetch = FetchType.EAGER)
private List<Comment> commentList=new ArrayList<>();
  • @OneToMany: ’Post’ 엔티티가 여러 개의 ‘Comment’ 엔티티를 가질 수 있다.
  • mappedBy = post: ’Comment’ 클래스에서 ‘post’ 필드에 의해 매핑된다는 것을 의미한다. 다시 말해, ‘Comment’ 엔티티에 있는 ‘post’ 필드로 연결된다.
  • fetch = FetchType.EAGER: ’fetch’속성은 데이터를 어떻게 가져올지 설정한다. ‘FetchType.Eager’은 관련 엔티티를 즉시 로딩하라는 것을 의미한다. 즉, ‘Post’엔터티를 조회할 때 함게 연관된 모든 ‘Comment’엔터티도 가져오게 된다.

→ 이 부분을 통해 ‘Post’ 엔터티를 조회할 때 해당 ‘Post’에 대한 모든 댓글 (’Comment’)도 함께 가져오게 된다. EAGER 로딩은 한 번에 모든 데이터를 가져오기 때문에 성능상의 이슈가 발생할 수 있으므로 신중하게 사용하는 것이 중요하다. 만약 성능상의 문제가 있을 경우, FetchType.Lazy 를 통해 필요한 시점에 데이터를 가져오도록 설정할 수 있다.

3-1. ManyToOne 관계

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "post_id", nullable = false)
private Post post;
  • @ManyToOne: 여러개의 ‘Comment’ 엔티티 하나의 ‘Post’ 엔티티에 속한다는 것을 나타낸다.
  • @JoinColumn:외래 키(Foreign Key)를 매핑하는 데 사용된다.
  • nullable = false: 이 필드는 null이 될 수 없다는 것을 나타낸다. 다시 말해 ‘Commnet’는 항상 특정 ‘Post’에 속해야 한다.

→ 이 관계 설정을 통해 ‘Comment’ 엔티티는 특정 ‘Post’ 엔티티에 속하게 된다.

  1. 정적 팩토리 메서드 (’from’ 메서드)
public static Post from(PostRequest postRequest) {
    Post post = new Post();
    // 내용 생략
    return post;
}
  • ‘form’ 메서드는 ‘PostRequest’ 객체를 받아 ‘Post’ 객체로 변환하는 정적 팩토리 메서드 이다.
  1. 댓글 추가 메서드 (’addComment’ 메서드)
gpublic Comment addComment(CommentRequest commentRequest) {
    Comment comment = new Comment();
    // 내용 생략
    return comment;
}
  • addComment’메서드는 ‘CommentRequest’ 객체를 받아 새로운 객체를 생성하고, 이를 현재 ‘Post’ 객체에 추가한다.


EntityManager

정의


JPA에서 Entity 객체(생명주기)를 관리하고 데이터베이스와의 상호작용을 담당하는 인터페이스 이다

주요 기능


  1. Entity Management: ‘EntityManager’은 Entity의 생명주기를 관리한다. Entity를 데이터베이스에 저장하거나 데이터베이스에서 조회, 수정, 삭제할 때 사용된다.

  2. Transaction Management: JPA에서 DB 조작은 트랜잭션 내에서 이루어져야 한다. ‘EntityManager’은 트랜잭션을 시작하고 커밋 또는 롤백하는 기능을 제공한다. 이를 통해 일관성 있는 데이터베이스 조작을 보장한다.

  3. 쿼리 수행 (Query Execution): JPAdptjsms JPAL(Java Persistence Query Language)라는 객체 지향적인 쿼리를 제공한다. ‘EntityManager’을 사용하여 JPQL을 실행하고 데이터베이스로부터 결과를 가져올 수 있다.

  4. 영속성 컨텍스트 (Persistence Context): ‘EntityManager’은 영속성 컨텍스트를 관리한다. 영속성 컨텍스트는 Entity 객체의 상태를 추적하고, 객체 간의 관계를 유지하는데 사용된다. 변경된 Entity는 트랜잭션 커밋 시에 데이터베이스에 반영된다.
  • 이때 생명주기란?
    → “생명주기”는 어던 개체나 시스템이 처음 생성되어 시작되고, 일정한 주기를 거쳐 성장하고 변경되며, 마지막으로 소멸되는 과정을 나타낸다. 객체, 소프트웨어 애플리케이션, 생물체, 하드웨어 등 다양한 컨텍스트에서 사용된다.

    → 객체의 생성주기는 객체가 생성되고 메모리에 할당된 시점부터 사용되고 변경되며, 더 이상 필요하지 않아 소멸될 때까지의 과정을 나타낸다. 이러한 과정을 객체의 생성, 초기화, 사용, 변경, 소멸 단계로 구성될 수 있다.

    → 소프트웨어 애플리케이션의 생명주기는 개발, 테스트, 배포, 운영, 유지보수 등의 단계로 나눌 수 있다. 이러한 단계를 통해 애플리케이션은 계속해서 발전하고 변화하며, 필요에 따라 업데이트 되거나 개선된다.

    → 컴퓨터 시스템의 생명주기는 하드웨어나 소프트웨어의 설계, 제조, 사용, 유지보수, 폐끼까지의 주기를 나타낸다.
  • 이때 트랜잭션 (Transaction)이란? → 트랜잭션은 DB의 상태를 변화시키기 위해서 수행되어야 하는 작업의 단위를 뜻한다. → 트랜잭션은 ACID 속성을 따라야 한다
    1. 원자성 (Atomicity): 트랜잭션의 모든 작업은 원자 단위로 처리되어야 하며, 모든 작업이 성공적으로 완료되거나 실패하면 롤백되어야 한다. 즉, 모든 작업이 성공하거나 아무것도 수행되지 않아야 한다.

    2. 일관성 (Consistenc): 트랜잭션이 완료된 후에도 데이터베이스는 일관된 상태여야 한다. 트랜잭션이 일어나기 전과 후에 데이터베이스의 무결성이 유지되어야 한다.

    3. 고립성 (Isolation): 여러 트랜잭션이 동시에 실행되더라도 각 트랜잭션은 서로 영향을 미치지 않고 독립적으로 수행되는 것처럼 보여야 한다. 한 트랜잭션의 부분 결과가 다른 트랜잭션에 노출되어서는 안 된다.

    4. 지속성 (Durability): 트랜잭션이 성공적으로 완료되면 해당 변경 내용은 영구적으로 데이터베이스에 반영되어야 하며, 시스템 장애 발생 시에도 유지되어야 한다.

      → 트랜잭션은 주로 데이터베이스에서 데이터의 무결성을 보장하고 일관성을 유지하기 위해 사용된다. 개발자는 트랜잭션을 사용하여 여러 작업을 우너자적으로 실행하고 DB를 안정적으로 유지할 수 있다.



계층형 구조

이미지 설명
  • controller, web: 웹 계층
  • service: 비지니스 로직, 트랜잭션 처리
  • repository: JPA를 직접 사용하는 계층, Entity Manager 사용
  • domain: Entity가 모여있는 계층, 모든 계층에서 사용

참고자료: https://dodeon.gitbook.io/study/kimyounghan-spring-boot-and-jpa-development/03-architecture

profile
컴퓨터공학/경영 전공생 :)

0개의 댓글

관련 채용 정보