JPA는 객체지향적 접근 방식
중요한 차이점은 SQL은 테이블 간의 관계를 직접 정의하는 반면, JPA는 객체지향적인 관계를 통해 테이블 간의 관계를 간접적으로 정의한다는 점입니다.
build.gradle
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.10'
id 'io.spring.dependency-management' version '1.1.6'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'com.h2database:h2'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
tasks.named('test') {
useJUnitPlatform()
}
application.yml
spring:
application:
name: demo
server:
port: 8080
datasource:
url: jdbc:h2:mem:testdb
driver-class-name: org.h2.Driver
username: sa
password:
jpa:
hibernate:
ddl-auto: create # 하이버네이트의 DDL 자동 실행 옵션 설정
h2:
console:
enabled: true # H2 콘솔 웹 인터페이스 활성화
path: /h2-console # H2 콘솔에 접근할 수 있는 경로 설정
# 디버깅을 위한 로깅 설정
logging:
level:
org:
springframework:
jdbc: DEBUG
hibernate:
SQL: DEBUG
JPA 사용해보기
Address Class
package com.example.demo.model;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class Address {
// @Id: 이 필드는 데이터베이스 테이블의 기본 키(primary key)를 나타냅니다.
// 이 어노테이션은 해당 필드가 엔티티의 고유 식별자임을 나타내며,
// 데이터베이스 테이블에서 이 필드를 기준으로 레코드를 구분합니다.
// @GeneratedValue(strategy = GenerationType.IDENTITY):
// 이 어노테이션은 기본 키가 자동으로 생성되도록 설정합니다.
// GenerationType.IDENTITY 전략은 데이터베이스의 "AUTO_INCREMENT" 기능을 사용하여
// 기본 키 값을 자동으로 생성합니다.
// 따라서, 새로운 엔티티가 데이터베이스에 삽입될 때마다
// 고유한 ID 값이 자동으로 생성되고 할당됩니다.
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String city;
private String street;
}
객체 지향 프로그래밍 언어에서 사용하는 객체 간의 관계를 관계형 데이터베이스의 테이블 간의 관계로 변환하는 과정입니다. JPA는 이러한 객체 간의 관계를 데이터베이스에 적절히 매핑할 수 있도록 다양한 매핑 방식을 지원합니다.
User와 Address 사이의 One-to-One 관계를 SQL로 표현할 때, 외래 키(FK)는 User 테이블이 Address 테이블을 참조하는 방식으로 설정됩니다. 즉, User 테이블이 Address 테이블의 기본 키(PK)를 외래 키로 참조하게 됩니다. 이로 인해 User는 특정 Address와 연결되고, Address는 User에 대해 아무런 정보를 가지지 않게 됩니다.
시나리오 코드2
Post, Comment 엔티티 만들어 보기
하나의 포스트(게시글)에 여러개의 코멘트(댓글)이 생긴다고 가정
Post 객체는 여러 개의 Comment 객체를 참조할 수 있습니다. 이는 List<Comment>를 통해 구현되며, 이를 통해 Post 객체는 자신과 연결된 여러 개의 댓글을 관리합니다. 반대로, Comment 객체는 각각 하나의 Post 객체를 참조합니다. 즉, 댓글은 항상 하나의 게시글에 속하게 됩니다.
Post와 Comment의 관계는 SQL 데이터베이스에서 **1:N (일대다)**관계로 정의됩니다. 즉, 하나의 게시글(Post)은 여러 개의 댓글(Comment)과 연결될 수 있습니다.
Post 테이블은 각 게시글에 대한 정보를 담고 있으며, 각 게시글은 고유한 ID로 식별됩니다. SQL에서 이를 나타내기 위해 기본 키(PK)를 설정합니다.
CREATE TABLE Post (
id BIGINT AUTO_INCREMENT PRIMARY KEY, -- 게시글의 고유 ID (PK)
title VARCHAR(255), -- 게시글 제목
content TEXT -- 게시글 내용
);
Comment 테이블은 각 댓글에 대한 정보를 담고 있으며, 각 댓글은 고유한 ID로 식별됩니다. 댓글은 어느 게시글에 속하는지를 나타내기 위해 외래 키(FK)를 사용합니다. 이 외래 키(FK)는 Post 테이블의 ID를 참조하며, 이를 통해 댓글이 어느 게시글에 속하는지 데이터베이스에서 관리됩니다.
CREATE TABLE Comment (
id BIGINT AUTO_INCREMENT PRIMARY KEY, -- 댓글의 고유 ID (PK)
text TEXT, -- 댓글 내용
post_id BIGINT, -- 어느 게시글에 속하는지 참조 (FK)
FOREIGN KEY (post_id) REFERENCES Post(id) -- Post 테이블의 id를 참조 (FK)
);
참조의 방향성
Post와 Comment 사이에서 참조의 방향성을 단방향 또는 양방향으로 설정할 수 있으며, 두 방식은 각각의 장단점이 있습니다. 실무에서는 보통 위와 같은 경우 양방향 참조를 많이 선택할 수 있지만 단방향성으로 만들더라도 잘못된 부분은 없습니다.
장점:
단점:
장점:
단점:
package com.example.demo.model;
import java.util.List;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Entity(name = "tb_comment")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Comment {
@Id // PK 지정
@GeneratedValue(strategy = GenerationType.IDENTITY) // 코드 --> db 위임
private Long id;
private String text;
@ManyToOne
@JoinColumn(name = "post_id")
private Post post;
}
package com.example.demo.model;
import java.util.List;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Entity(name = "tb_post")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String content;
// mappedBy : post - 연관 관계의 주인이 Comment 엔티티에 post(속성) 필드 임을 나타냅니다.
// 객체 필드 기준으로 생각해야 합니다.
// CascadeType.ALL - 제약을 설정하게 되면 Post 엔티티에 대한 모든 상태 변경(저장, 삭제 등)이
// 관련된 Commnet 엔티티에 전파 된다.
@OneToMany(mappedBy = "post" , cascade = CascadeType.ALL)
private List<Comment> comments;
}
시나리오 코드 3
Order 엔티티 만들어 보기 주문 서비스에서는 사용자(User)가 배송지(Address)로 물품을 주문(Order)하는 과정이 필요합니다
프로젝트 요구 조건에 따라서 참조의 방향성을 선택할 수 있지만 여기서는 User와 Address 엔티티와의 단방향 참조 관계를 설정해서 코드를 작성해 봅시다.
JAVA - 데이터 무결성(Data Integrity), 데이터 정합성(Data Consistency) (0) | 2024.10.02 |
---|---|
JAVA - 영속성 컨텍스트(Persistence Context) (0) | 2024.09.30 |
JAVA - 엔티티 매니저 (EntityManager) (0) | 2024.09.30 |
JAVA - JPA, 하이버네이트(Hibernate) (0) | 2024.09.30 |
JAVA - 스프링 부트 DB 접근 기술 ORM (0) | 2024.09.30 |