JAP는 자바 진영에서 객체관계 매핑 (ORM)을 위한 API (인터페이스 모음)이자 Java Persistence Framework (자바 영속성 프레임워크)중 하나로, 데이터베이스와 자바 객체 간의 매핑을 편리하게 처리하는 기술이다. JAP를 사용하면 개발자는 SQL 쿼리를 직접 작성하지 않고도 객체 지향적인 방식으로 데이터를 다룰 수 있다. JAP는 대표적으로 Hibernate, EclipseLink와 같은 구현체를 사용하여 데이터베이스와 상호 작용한다. MyBatis또한 자바 영속성 프레임워크에 속하지만, JPA는 조금 더 객체지향적인 반면, MyBatis는 SQL에 대한 유연성이 더 높다.
객체와 관계형 데이터 베이스 간의 매핑을 의미한다. 이는 객체 지향 프로그래밍 언어에서 사용되는 객체와 데이터베이스 테이블 사이의 관계를 매핑하는 기술이다. ORM을 사용하면 데이터베이스에서 직접 SQL 쿼리를 작성하는 대신, 객체 지향 프로그래밍 언어에서 제공하는 메서드와 속성을 사용하여 데이터베이스를 다룰 수 있다. 이를 통해 개발자는 데이터베이스와의 상호 작용을 더 추상화하고, 코드를 더 간결하게 작성할 수 있다.
개발 생산성을 향상시키고 코드의 유지보수성을 높일 수 있다. ORM 프레임워크를 사용하면 데이터베이스와의 상호 작용을 추상화하여 더 효율적으로 코드를 작성하고 유지보수 할 수 있다.
JPA에서 데이터베이스의 테이블과 매핑되는 자바 객체를 나타낸다.
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임을 나타낸다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;
}
}
@Entity
@Setter
@NoArgsConstructor
@Getter
public class Post {
// 클래스 내용
}
@Setter, @NoArgsConstructor, @Getter:
Lombok 어노테이션으로 Getter, Setter, 기본생성자를 자동으로 생성한다.@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:
데이터베이스 컬럼에 대한 매핑 정보를 제공한다.@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’ 엔티티에 속하게 된다.
public static Post from(PostRequest postRequest) {
Post post = new Post();
// 내용 생략
return post;
}
gpublic Comment addComment(CommentRequest commentRequest) {
Comment comment = new Comment();
// 내용 생략
return comment;
}
JPA에서 Entity 객체(생명주기)를 관리하고 데이터베이스와의 상호작용을 담당하는 인터페이스 이다
원자성 (Atomicity): 트랜잭션의 모든 작업은 원자 단위로 처리되어야 하며, 모든 작업이 성공적으로 완료되거나 실패하면 롤백되어야 한다. 즉, 모든 작업이 성공하거나 아무것도 수행되지 않아야 한다.
일관성 (Consistenc): 트랜잭션이 완료된 후에도 데이터베이스는 일관된 상태여야 한다. 트랜잭션이 일어나기 전과 후에 데이터베이스의 무결성이 유지되어야 한다.
고립성 (Isolation): 여러 트랜잭션이 동시에 실행되더라도 각 트랜잭션은 서로 영향을 미치지 않고 독립적으로 수행되는 것처럼 보여야 한다. 한 트랜잭션의 부분 결과가 다른 트랜잭션에 노출되어서는 안 된다.
지속성 (Durability): 트랜잭션이 성공적으로 완료되면 해당 변경 내용은 영구적으로 데이터베이스에 반영되어야 하며, 시스템 장애 발생 시에도 유지되어야 한다.
→ 트랜잭션은 주로 데이터베이스에서 데이터의 무결성을 보장하고 일관성을 유지하기 위해 사용된다. 개발자는 트랜잭션을 사용하여 여러 작업을 우너자적으로 실행하고 DB를 안정적으로 유지할 수 있다.
참고자료: https://dodeon.gitbook.io/study/kimyounghan-spring-boot-and-jpa-development/03-architecture