๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

JPA

ORM(Object Relational Mapping)

ORM(Object Relational Mapping)

๊ฐ์ฒด์ง€ํ–ฅ ์–ธ์–ด๋กœ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค๋ฅผ ์ด์šฉํ•ด ๊ฐœ๋ฐœํ•  ๋•Œ ํ•„์š”ํ•œ ORM์„ ์•Œ์•„๋ณด์ž.

ORM ์ด๋ž€?

Object Relational Mapping : ๊ฐ์ฒด ๊ด€๊ณ„ ๋งคํ•‘

์ด๋ฆ„ ๊ทธ๋Œ€๋กœ ๊ฐ์ฒด๋ฅผ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค์— ๋งž๊ฒŒ ๋งคํ•‘ํ•ด์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

๋” ํ’€์–ด์„œ ์–˜๊ธฐํ•˜๋ฉด ๊ฐ์ฒด์ง€ํ–ฅ๊ณผ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ํŒจ๋Ÿฌ๋‹ค์ž„ ๋ถˆ์ผ์น˜๋ฅผ ํ•ด๊ฒฐํ•ด ์ฃผ๊ณ  ๊ฐ์ฒด๋กœ ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค ๋ชจ๋ธ์„ ๋งŒ๋“ค์–ด์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

๊ฐ์ฒด์ง€ํ–ฅ๊ณผ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ํŒจ๋Ÿฌ๋‹ค์ž„ ๋ถˆ์ผ์น˜

์›น์‚ฌ์ดํŠธ๋ฅผ ๋งŒ๋“ ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž.

์›น์‚ฌ์ดํŠธ๋ฅผ ์ด์šฉํ•  User๊ฐ€ ์žˆ๊ณ , ๊ทธ User๋Š” ์›น์‚ฌ์ดํŠธ์—์„œ ์ž๊ธฐ๊ฐ€ ๊ด€๋ฆฌํ•ด์•ผ ํ•˜๋Š” ์ผ(Task)์ด ํ•„์š”ํ•˜๋‹ค๊ณ  ํ•˜์ž.

RDB์—์„  User Table๊ณผ Task Table์„ ๋งŒ๋“ค๊ณ , Task ํ…Œ์ด๋ธ”์—์„œ User์˜ PK(Primary Key)๋ฅผ FK(Foreign Key)๋กœ ์ €์žฅํ•˜์—ฌ ํ•„์š”ํ•  ๋•Œ Join์„ ํ†ตํ•ด Task๋ฅผ ์ž‘์„ฑํ•œ ์œ ์ €๋ฅผ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ฐ์ฒด์ง€ํ–ฅ์—์„œ๋Š” User์™€ Task์— ๋Œ€ํ•œ ๊ฐ์ฒด๋ฅผ ์–ด๋–ป๊ฒŒ ๋งŒ๋“ค๊นŒ?

User.java

public class User{
  private Long id;
  // ...
}

Task.java

public class Task{
  private Long id;
  private User user;
  // ...
}

RDB์—์„  ๊ฐ์ฒด ์ž์ฒด๋ฅผ ๋‹ด์„ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— FK๋กœ ์ฐธ์กฐํ•ด์•ผ ํ•˜์ง€๋งŒ, ๊ฐ์ฒด์ง€ํ–ฅ์—์„  ์œ„์˜ ์ฝ”๋“œ์ฒ˜๋Ÿผ User ๊ฐ์ฒด๋ฅผ ๊ฐ์ฒด ์ž์ฒด๋กœ ๋ ˆํผ๋Ÿฐ์Šค์— ์˜ํ•œ ์ฐธ์กฐ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด๋Ÿฐ ๊ฐ์ฒด์ง€ํ–ฅ๊ณผ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ํŒจ๋Ÿฌ๋‹ค์ž„ ๋ถˆ์ผ์น˜๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ORM์„ ์‚ฌ์šฉํ•œ๋‹ค.

ORM์˜ ์‚ฌ์šฉ

ORM์ด ๋“ฑ์žฅํ•˜๊ธฐ ์ „ ๊ธฐ์กด์˜ ๋ฐฉ์‹์€ ๋จผ์ € ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค์˜ ํ…Œ์ด๋ธ”์„ ๋ชจ๋ธ๋ง ํ•œ ํ›„ ๊ทธ์— ๋งž์ถฐ์„œ ๊ฐ์ฒด์ง€ํ–ฅ์—์„œ ์ฝ”๋“œ๋กœ ๊ตฌํ˜„ํ–ˆ๋‹ค.

๊ทธ๋Ÿฌ๋ฏ€๋กœ ์œ„์ฒ˜๋Ÿผ ๋ ˆํผ๋Ÿฐ์Šค๋กœ ์ฐธ์กฐํ•˜๋Š” ๋ฐฉ์‹์ด ์•„๋‹Œ, User ํ…Œ์ด๋ธ”์˜ FK๋ฅผ Task ๊ฐ์ฒด์— ์ €์žฅํ•ด ์ฃผ์—ˆ๋‹ค.

RDB์— ๋งž์ถฐ์ง„ ๊ฐ์ฒด ์„ค๊ณ„

public class Task{
  private Long id;
  private Long user_id;
  // ...
}

๊ฐ์ฒด์ง€ํ–ฅ์ ์ด์ง€ ๋ชปํ•œ ์ฝ”๋“œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋œ ๊ฒƒ์ด๋‹ค.

ORM์€ Object Relational Mapping, ๋ง ๊ทธ๋Œ€๋กœ ๊ฐ์ฒด๋ฅผ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋งคํ•‘ํ•ด์ฃผ๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ์กด์˜ ๋ฐฉ์‹์ฒ˜๋Ÿผ ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค์˜ ํ…Œ์ด๋ธ”์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค.

๊ฐ์ฒด์ง€ํ–ฅ์—์„œ Entity๋ฅผ ๋จผ์ € ์„ค๊ณ„ํ•˜๋ฉด, ORM์ด ๊ทธ์— ๋งž์ถฐ RDB์˜ ํ…Œ์ด๋ธ”์„ ๋งŒ๋“ค์–ด์ค€๋‹ค.

JPA ์˜ˆ์ œ

JPA์—์„œ User์™€ Task ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค๊ณ , ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๊ทธ์— ๋งคํ•‘๋œ FK๋ฅผ ๊ฐ–๊ณ  ์žˆ๋Š” ํ…Œ์ด๋ธ”์ด ๋งŒ๋“ค์–ด์ง€๋Š”์ง€ ํ™•์ธํ•˜์ž.

User.java

package com.vividswan.studymate.model;

import lombok.*;
import org.hibernate.annotations.CreationTimestamp;
import org.springframework.data.annotation.CreatedDate;

import javax.persistence.*;
import java.sql.Timestamp;
import java.time.LocalDateTime;

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

    @Column(nullable = false, length = 100, unique = true)
    private String username;
    @Column(nullable = false, length = 100)
    private String nickname;
    @Column(nullable = false, length = 50)
    private String email;
    @Column(nullable = false, length = 100)
    private String password;

    @Enumerated(EnumType.STRING)
    private RoleType role;

    @CreationTimestamp
    private LocalDateTime createDate;

    public void update(String password, String nickname, String email){
        this.password = password;
        this.nickname = nickname;
        this.email=email;
    }
}

Task.java

package com.vividswan.studymate.model;

import lombok.*;
import org.hibernate.annotations.CreationTimestamp;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.format.annotation.DateTimeFormat;

import javax.persistence.*;
import java.sql.Timestamp;
import java.time.LocalDateTime;

@NoArgsConstructor
@AllArgsConstructor
@Builder
@Getter
@Entity
public class Task {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false,length = 100)
    private String title;

    @Lob
    private String content;

    @CreationTimestamp
    private LocalDateTime createDate;

    private LocalDateTime deadline;

    @ManyToOne
    @JoinColumn(name="userId")
    private User user;

    private int isSuccess;
}

๋‹ค์Œ๊ณผ ๊ฐ™์ด User์™€ Task ๊ฐ์ฒด๋ฅผ ์ž‘์„ฑํ–ˆ๋‹ค.

Task ์ฝ”๋“œ์—์„œ User๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๋ถ€๋ถ„์„ ํ™•์ธํ•ด๋ณด์ž.

//...
    @ManyToOne
    @JoinColumn(name="userId")
    private User user;
//...

์–ด๋…ธํ…Œ์ด์…˜์„ ๊ฐ„๋‹จํžˆ ์‚ดํŽด๋ณด์ž๋ฉด,

@ManyToOne : ๋‹ค์ˆ˜์˜ Task๊ฐ€ ํ•œ ๋ช…์˜ User์— ์˜ํ•ด ์ž‘์„ฑ๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ Many(Task)toOne(User)์ด๋‹ค.

@JoinColumn(name="userId") : ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ”์„ ์ž‘์„ฑํ•  ๋•Œ ์นผ๋Ÿผ์— ์ด๋ฆ„์€ userId์ธ user๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋Š” PK๋ฅผ ์ƒ์„ฑํ•ด๋‹ฌ๋ผ๋Š” ๊ฒƒ์ด๋‹ค.

private User user;์—์„œ ์•Œ ์ˆ˜ ์žˆ๋“ฏ์ด, ๊ฐ์ฒด์ง€ํ–ฅ์˜ ์„ค๊ณ„์— ๋งž๊ฒŒ PK๊ฐ€ ์•„๋‹Œ ๊ฐ์ฒด ๋ž˜ํผ๋Ÿฐ์Šค๋กœ ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋‹ค.

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ํ™•์ธ

๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ž˜ ๋งคํ•‘์ด ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ด๋ณด์ž.

User์— ๋Œ€ํ•œ PK๊ฐ€ ๋งคํ•‘๋์Œ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด์ฒ˜๋Ÿผ ORM์€ ์ž๋ฐ”๊ฐ€ ์ฃผ๋„๊ถŒ์ด ์žˆ๋Š” ๋ชจ๋ธ์„ ๋งŒ๋“ค์–ด์„œ ํŒจ๋Ÿฌ๋‹ค์ž„ ๋ถˆ์ผ์น˜๋ฅผ ํ•ด๊ฒฐํ•ด ์ค„ ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค.