๐ก
1. JPA๋ฅผ ์ฌ์ฉํ์ฌ User์ Board ์ํฐํฐ ๊ฐ์ ์ฐ๊ด ๊ด๊ณ๋ฅผ ์ค์ ํ ์ ์๋ค.
2. @ManyToOne๊ณผ @OneToMany ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉ๋ฒ๊ณผ ์๋ฏธ๋ฅผ ์ดํดํ๋ค.
3. ์ง์ฐ ๋ก๋ฉ(FetchType.LAZY)์ ๋์ ๋ฐฉ์์ ์ดํดํ๋ค.
4. @JoinColumn ์ด๋ ธํ ์ด์ ์ ์ญํ ์ ์ค๋ช ํ ์ ์๋ค.
Board ์ํฐํฐ ์์ ํ๊ธฐ - user ์์ฑ ์ถ๊ฐ
Board ์ํฐํฐ์ User์์ ์ฐ๊ด ๊ด๊ณ๋ฅผ ์ค์ ํฉ์๋ค.
์์ ๋ Board ์ํฐํฐ ์ฝ๋
package com.tenco.blog_v1.board;
import com.tenco.blog_v1.user.User;
import jakarta.persistence.*;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.sql.Timestamp;
@NoArgsConstructor
@Entity
@Table(name = "board_tb")
@Data
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // ๊ธฐ๋ณธํค ์ ๋ต db ์์
private Integer id;
private String title;
private String content;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "user_id")
private User user; // ๊ฒ์๊ธ ์์ฑ์ ์ ๋ณด
// created_at ์ปฌ๋ผ๊ณผ ๋งคํํ๋ฉฐ, ์ด ํ๋๋ ๋ฐ์ดํฐ ์ ์ฅ์ ์๋์ผ๋ก ์ค์ ๋จ
@Column(name = "created_at", insertable = false, updatable = false)
private Timestamp createdAt;
@Builder
public Board(Integer id, String title, String content, User user, Timestamp createdAt) {
this.id = id;
this.title = title;
this.content = content;
this.user = user;
this.createdAt = createdAt;
}
}
์ฝ๋ ์ค๋ช
- @Entity: ์ด ํด๋์ค๊ฐ JPA ์ํฐํฐ์์ ๋ํ๋ ๋๋ค.
- @Table(name = "board_tb"): ์ํฐํฐ์ ๋งคํ๋ ํ ์ด๋ธ ์ด๋ฆ์ ์ง์ ํฉ๋๋ค.
- @Id, @GeneratedValue: ๊ธฐ๋ณธ ํค ํ๋๋ฅผ ์ค์ ํฉ๋๋ค.
- @ManyToOne(fetch = FetchType.LAZY):
- Board ์ํฐํฐ๊ฐ User ์ํฐํฐ์ ๋ค๋์ผ ๊ด๊ณ์์ ๋ํ๋ ๋๋ค.
- ์ง์ฐ ๋ก๋ฉ(LAZY): ์ค์ ๋ก user ํ๋๊ฐ ์ฌ์ฉ๋ ๋๊น์ง ๋ก๋ฉ์ ์ง์ฐ์ํต๋๋ค.
- @JoinColumn(name = "user_id"):
- ์ธ๋ ํค ์ปฌ๋ผ์ ์ด๋ฆ์ user_id๋ก ์ง์ ํฉ๋๋ค.
- ์ด ์ปฌ๋ผ์ ํตํด User ์ํฐํฐ์ ์ฐ๊ฒฐ๋ฉ๋๋ค.
- private User user;: ์์ฑ์ ์ ๋ณด๋ฅผ ๋ํ๋ด๋ ํ๋์ ๋๋ค
User ์ํฐํฐ ์์ฑํ๊ธฐ
User ์ํฐํฐ์ Board์์ ์ฐ๊ด ๊ด๊ณ๋ฅผ ์ค์ ํ์ฌ, ์ฌ์ฉ์๊ฐ ์์ฑํ ๊ฒ์๊ธ ๋ชฉ๋ก์ ๊ฐ์ ธ์ฌ ์ ์๋๋ก ํฉ๋๋ค.
package com.tenco.blog_v1.user;
import com.tenco.blog_v1.board.Board;
import jakarta.persistence.*;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.CreationTimestamp;
import java.sql.Timestamp;
import java.util.List;
@NoArgsConstructor
@Data
@Entity
@Table(name = "user_tb")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(unique = true) // ์ ๋ํฌ ์ ์ฝ ์กฐ๊ฑด ์ค์
private String username;
private String password;
private String email;
@CreationTimestamp // ์ํฐํฐ ์์ฑ์ ์๋์ผ๋ก ํ์ฌ ์๊ฐ ์
๋ ฅ
private Timestamp createdAt;
// ๋จ๋ฐฉํฅ, ์๋ฐฉํฅ ๋งคํ(mappedBy)
// @OneToMany(mappedBy = "user", fetch = FetchType.LAZY) // ์ง์ฐ ๋ก๋ฉ ์ค์
@OneToMany(mappedBy = "user", fetch = FetchType.EAGER) // ์ฆ์ ๋ก๋ฉ ์ค์
private List<Board> boards;
@Builder
public User(Integer id, String username, String password, String email, Timestamp createdAt, List<Board> boards) {
this.id = id;
this.username = username;
this.password = password;
this.email = email;
this.createdAt = createdAt;
this.boards = boards;
}
}
์ฝ๋ ์ค๋ช
- @OneToMany(mappedBy = "user", fetch = FetchType.LAZY):
- User ์ํฐํฐ๊ฐ Board ์ํฐํฐ์ ์ผ๋๋ค ๊ด๊ณ์์ ๋ํ๋ ๋๋ค.
- mappedBy = "user": Board ์ํฐํฐ์ user ํ๋์ ์ํด ๋งคํ๋จ์ ๋ํ๋ ๋๋ค.
- ์ง์ฐ ๋ก๋ฉ(LAZY): ์ค์ ๋ก boards ํ๋๊ฐ ์ฌ์ฉ๋ ๋๊น์ง ๋ก๋ฉ์ ์ง์ฐ์ํต๋๋ค.
- private List<Board> boards;: ์ฌ์ฉ์๊ฐ ์์ฑํ ๊ฒ์๊ธ ๋ชฉ๋ก์ ์ ์ฅํฉ๋๋ค.
์ฐ๊ด ๊ด๊ณ๊ฐ ์ค์ ๋ ์ํฐํฐ์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ ํ์ฌ ์ค์ ๋ก ์ด๋ป๊ฒ ๋งคํ๋๋์ง ํ์ธ.
์ํ ๋ฐ์ดํฐ ์ ๋ ฅ
-- ์ฌ์ฉ์ ๋ฐ์ดํฐ ์ฝ์
INSERT INTO user_tb(username, password, email, created_at) VALUES('๊ธธ๋', '1234', 'a@nate.com', NOW());
INSERT INTO user_tb(username, password, email, created_at) VALUES('๋๋ฆฌ', '1234', 'b@nate.com', NOW());
INSERT INTO user_tb(username, password, email, created_at) VALUES('๋ง์ด์ฝ', '1234', 'c@nate.com', NOW());
-- ๊ฒ์๊ธ ๋ฐ์ดํฐ ์ฝ์
INSERT INTO board_tb(title, content, user_id, created_at) VALUES('์ ๋ชฉ1', '๋ด์ฉ1', 1, NOW());
INSERT INTO board_tb(title, content, user_id, created_at) VALUES('์ ๋ชฉ2', '๋ด์ฉ2', 1, NOW());
INSERT INTO board_tb(title, content, user_id, created_at) VALUES('์ ๋ชฉ3', '๋ด์ฉ3', 2, NOW());
INSERT INTO board_tb(title, content, user_id, created_at) VALUES('์ ๋ชฉ4', '๋ด์ฉ4', 3, NOW());
user_id ์ปฌ๋ผ์ ํตํด Board์ User๊ฐ ์ฐ๊ด ๊ด๊ณ๋ฅผ ๋งบ๊ณ ์์ต๋๋ค.
Hibernate๊ฐ ์์ฑํ DDL
Hibernate:
drop table if exists board_tb cascade
Hibernate:
drop table if exists user_tb cascade
Hibernate:
create table board_tb (
id integer generated by default as identity,
user_id integer,
created_at timestamp(6),
content varchar(255),
title varchar(255),
primary key (id)
)
Hibernate:
create table user_tb (
id integer generated by default as identity,
created_at timestamp(6),
email varchar(255),
password varchar(255),
username varchar(255) unique,
primary key (id)
)
Hibernate:
alter table if exists board_tb
add constraint FKgxwryj58kh66twbp656wo5gnn
foreign key (user_id)
references user_tb
board_tb ํ ์ด๋ธ์ user_id ์ปฌ๋ผ์ด ์ธ๋ ํค(Foreign Key)๋ก ์ค์ ๋์ด user_tb ํ ์ด๋ธ์ id ์ปฌ๋ผ๊ณผ ์ฐ๊ด๋ฉ๋๋ค.
ํต์ฌ ๊ฐ๋ ์ ๋ฆฌ
1) ์ฐ๊ด ๊ด๊ณ ๋งคํ ์ค์
- @ManyToOne: Board ์ํฐํฐ์์ User ์ํฐํฐ์์ ๋ค๋์ผ ๊ด๊ณ๋ฅผ ์ค์ ํฉ๋๋ค.
- @OneToMany: User ์ํฐํฐ์์ Board ์ํฐํฐ์์ ์ผ๋๋ค ๊ด๊ณ๋ฅผ ์ค์ ํฉ๋๋ค.
- mappedBy: ์ฐ๊ด ๊ด๊ณ์ ์ฃผ์ธ์ ์ค์ ํ ๋ ์ฌ์ฉํ๋ฉฐ, ์ฐ๊ด ๊ด๊ณ์ ์ฃผ์ธ์ด ์๋ ์ชฝ์์ ์ฌ์ฉํฉ๋๋ค.
2) ์ง์ฐ ๋ก๋ฉ (FetchType.LAZY)
- ์ง์ฐ ๋ก๋ฉ(LAZY): ์ฐ๊ด๋ ์ํฐํฐ๋ฅผ ์ค์ ๋ก ์ฌ์ฉํ ๋๊น์ง ๋ฐ์ดํฐ๋ฒ ์ด์ค ์กฐํ๋ฅผ ์ง์ฐ์ํต๋๋ค.
- ์ฆ์ ๋ก๋ฉ(EAGER): ์ํฐํฐ๊ฐ ๋ก๋ฉ๋ ๋ ์ฐ๊ด๋ ์ํฐํฐ๋ ํจ๊ป ๋ก๋ฉํฉ๋๋ค.
- ์ฌ์ฉ ์ด์ : ๋ถํ์ํ ๋ฐ์ดํฐ ๋ก๋ฉ์ ๋ฐฉ์งํ์ฌ ์ฑ๋ฅ์ ์ต์ ํํ๊ธฐ ์ํด ์ฌ์ฉํฉ๋๋ค.
3) @JoinColumn ์ด๋ ธํ ์ด์
- ์ญํ : ์ธ๋ ํค ์ปฌ๋ผ์ ๋ช ์์ ์ผ๋ก ์ง์ ํ์ฌ, ์ฐ๊ด ๊ด๊ณ๋ฅผ ๋งคํํฉ๋๋ค.
- ์ฌ์ฉ ์์น: ์ฐ๊ด ๊ด๊ณ์ ์ฃผ์ธ(Owner) ์ชฝ ์ํฐํฐ์ ํ๋์ ์ ์ฉํฉ๋๋ค.