JPA
Entity
์์์ฑ ์ปจํ ์คํธ
1. JPA๋ ๋ฌด์์ธ๊ฐ?
: ์๋ฅผ ๋ค์ด ์ด์ ํ๋ก์ ํธ์์(ORM์ด ์๋ ํ๊ฒฝ) ์ด๋ค ์ปฌ๋ผ ํ๋๋ฅผ ์ถ๊ฐํ์ ๋ ๊ทธ์ ๋ฐ๋ฅธ ์ถ๊ฐ์ ์ธ SQL ์์ ์ด ๋ฌด์ํ ๋ง์์ง๋ค. ์ด๋ก ์ธํด ๋น์ง๋์ค ๋ก์ง ๊ฐ๋ฐ๋ณด๋ค SQL ์์ฑ ๋ฐ ์์ ์ ๋ ๋ง์ ์๊ฐ์ ํ ์ ํ๋ค.
๊ทธ๋์ ORM ์ด ๋ฑ์ฅํ๊ฒ ๋์๋ค. Object Relational Mapping์ ์ค์๋ง๋ก ์๋ฐ ํด๋์ค์ DB data ๋ฅผ mapping ํ๋ ๋ฒ๊ฑฐ๋ก์ด ์์ ์ ORM์ด ์๋์ผ๋ก ์ฒ๋ฆฌํด์ค๋ค. (์ง์ DB๋ฅผ ๋ค๋ฃจ์ง ์์๋ ๋จ~)
# JPA๋ ORM ๊ธฐ์ ์ ๋ํ ํ์ค ๋ช ์ธ
- ๊ทธ๋ฆฌ๊ณ JPA๋ฅผ ๊ตฌํํ ํ๋ ์์ํฌ ์ค ๊ฐ์ฅ ๋ง์ด ์ฐ์ด๋ ๊ฒ์ด 'ํ์ด๋ฒ๋ค์ดํธ' ์ด๋ค! (์์ฃผ ๋ฑ์ฅ ์์ )
2. Entity๋ ๋ฌด์์ผ๊น?
: JPA์ ์ํด ๊ด๋ฆฌ๋๋ ํด๋์ค ์ฆ ๊ฐ์ฒด์ด๋ค.
-Entityํด๋์ค๋ DB ํ ์ด๋ธ๊ณผ ๋งคํ๋์ด JPA์ ์ํด ๊ด๋ฆฌ๋๋ค.
#ํ๋ก์ ํธ ์ค์ ์ถ๊ฐ
src main resources META-INF persistence.xml
build.gradle์ JPA, MySQL ์ถ๊ฐ / ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ฑ ํ ์ฐ๊ฒฐ ํ์.
- EntityTest
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public class EntityTest {
EntityManagerFactory emf;
EntityManager em;
@BeforeEach
void setUp() {
emf = Persistence.createEntityManagerFactory("memo");
em = emf.createEntityManager();
}
@Test
void test1() {
}
}
-> ์คํ ํ Hibernate์์ create table memo / ์ง์ ์์ฑํ๋ ๊ฒ์ด ์๋ JPA์์ @Entity์ ๋ณด๋ฅผ ์ฝ๊ณ ๋ง๋ค์ด์ค๋ค.
- Entity ํด๋์ค ๋ง๋ค๊ธฐ
@Entity // JPA๊ฐ ๊ด๋ฆฌํ ์ ์๋ Entity ํด๋์ค ์ง์
@Table(name = "memo") // ๋งคํํ ํ
์ด๋ธ์ ์ด๋ฆ์ ์ง์
public class Memo {
@Id
private Long id;
// nullable: null ํ์ฉ ์ฌ๋ถ
// unique: ์ค๋ณต ํ์ฉ ์ฌ๋ถ (false ์ผ๋ ์ค๋ณต ํ์ฉ)
@Column(name = "username", nullable = false, unique = true)
private String username;
// length: ์ปฌ๋ผ ๊ธธ์ด ์ง์
@Column(name = "contents", nullable = false, length = 500)
private String contents;
}
@Entity: ํด๋น ์ ๋ํ ์ด์ ์ผ๋ก JPA๊ฐ ๊ด๋ฆฌํ ์ ์๋ Entity ํด๋์ค๋ก ์ง์ ํ ์ ์๋ค.
@Table(name="memo"): ๋งคํํ ํ ์ด๋ธ์ ์ง์ ํด์ค๋ค.
- @GeneratedValue ์ต์
@Entity // JPA๊ฐ ๊ด๋ฆฌํ ์ ์๋ Entity ํด๋์ค ์ง์
@Table(name = "memo") // ๋งคํํ ํ
์ด๋ธ์ ์ด๋ฆ์ ์ง์
public class Memo {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// nullable: null ํ์ฉ ์ฌ๋ถ
// unique: ์ค๋ณต ํ์ฉ ์ฌ๋ถ (false ์ผ๋ ์ค๋ณต ํ์ฉ)
@Column(name = "username", nullable = false, unique = true)
private String username;
// length: ์ปฌ๋ผ ๊ธธ์ด ์ง์
@Column(name = "contents", nullable = false, length = 500)
private String contents;
}
@Id ์๋ณ์์ญํ (PK)
@GeneratedValue -> AUTO_INCREMENT ์๋์ผ๋ก ํด์ค๋ค.
- ๋ค์ run ํด์ ๋ง๋ค์ด์ง ํ ์ด๋ธ ํ์ธํด๋ณด๋ฉด id auto_increment ๋์ด ์๋ ๊ฑธ ํ์ธํ ์ ์๋ค.
- ํด๋น ์ต์ ์ ์ถ๊ฐํด์ฃผ๋ฉด ์ง์ id๊ฐ์ ๋ฃ์ด์ฃผ์ง ์์๋ ์๋์ผ๋ก ์์์ ๋ง๊ฒ ๊ธฐ๋ณธ ํค๊ฐ ์ถ๊ฐ๋๋ค.
3. ์์์ฑ ์ปจํ ์คํธ๋ ๋ฌด์์ผ๊น?
- Entity๊ฐ์ฒด๋ฅผ ํจ์จ์ ์ผ๋ก ์ฝ๊ฒ ๊ด๋ฆฌํ๊ธฐ ์ํด ๋ง๋ค์ด์ง ๊ณต๊ฐ์ด๋ค.
SQL์ ์ง์ ์์ฑํ์ง ์์๋ JPA๋ฅผ ์ฌ์ฉํ์ฌ DB์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ฑฐ๋ ์กฐํํ ์ ์์ผ๋ฉฐ ์์ , ์ญ์ ๋ํ ๊ฐ๋ฅํ๋ค.
์ด๋ฐ ์ผ๋ จ์ ๊ณผ์ ์ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ๊ธฐ ์ํด JPA๋ ์์์ฑ ์ปจํ ์คํธ์ Entity ๊ฐ์ฒด๋ค์ ์ ์ฅํ์ฌ ๊ด๋ฆฌํ๋ฉฐ DB์ ์ํตํ๋ค.
- Entity Manager
- Entity๋ฅผ ๊ด๋ฆฌํ๋ ๊ด๋ฆฌ์์ด๋ค. ์์์ฑ ์ปจํ ์คํธ์ ์ ๊ทผํ์ฌ Entity ๊ฐ์ฒด๋ค์ ์กฐ์ํ๊ธฐ ์ํด ํ์ํ๋ค.
- EntityManagerFactory๋ฅผ ํตํด ์์ฑํ์ฌ ์ฌ์ฉํ ์ ์๋ค.
- EntityManagerFactory
- ์ผ๋ฐ์ ์ผ๋ก DB ํ๋์ ํ๋๋ง ์์ฑ๋์ด ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋์ํ๋ ๋์ ์ฌ์ฉ๋๋ค.
- ์ด๋ฅผ ๋ง๋ค๊ธฐ ์ํด์๋ DB์ ๋ํ ์ ๋ณด๋ฅผ ์ ๋ฌํด์ผ ํ๋ฉฐ /resources/META-INF/ ์์น์ persistence.xml ํ์ผ์ ๋ง๋ค์ด ์ ๋ณด๋ฅผ ์ ์ฅํ๋ฉด ๋๋ค.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("memo");
//ํด๋น ์ฝ๋๋ก JPA๋ persistence.xml์ ์ ๋ณด๋ฅผ ํ ๋๋ก emf๋ฅผ ์์ฑ
EntityManager em = emf.createEntityManager();
//emf๋ฅผ ์ฌ์ฉํ์ฌ em๋ฅผ ์์ฑ
# ํธ๋์ญ์ ์ด๋?
- ํธ๋์ญ์ ์ DB ๋ฐ์ดํฐ๋ค์ ๋ฌด๊ฒฐ์ฑ๊ณผ ์ ํฉ์ฑ์ ์ ์งํ๊ธฐ ์ํ ํ๋์ ๋ ผ๋ฆฌ์ ๊ฐ๋ ์ด๋ค. (์ฝ๊ฒ ๋งํด DB ๋ฐ์ดํฐ๋ฅผ ์์ ํ๊ฒ ๊ด๋ฆฌํ๊ธฐ ์ํจ)
- ๊ฐ์ฅ ํฐ ํน์ง์ ์ฌ๋ฌ SQL์ด ํ๋์ ํธ๋์ญ์ ์ ํฌํจ๋ ์ ์๋ ์ ์ด๋ค.
- ๋ชจ๋ SQL์ด ์ฑ๊ณต์ ์ผ๋ก ์ํ๋๋ฉด DB์ ์๊ตฌ์ ์ผ๋ก ๋ฐ์๋๋ SQL ์ค ํ๋๋ผ๋ ์คํจํ๋ฉด ๋ชจ๋ ๋ณ๊ฒฝ์ ๋๋๋ฆฐ๋ค.
*ํธ๋์ญ์ ํ์ธํ๊ธฐ (MySQL)
START TRANSACTION; # ํธ๋์ญ์
์ ์์ํฉ๋๋ค.
INSERT INTO memo (id, username, contents) VALUES (1, 'Robbie', 'Robbie Memo');
INSERT INTO memo (id, username, contents) VALUES (2, 'Robbert', 'Robbert Memo');
SELECT * FROM memo;
COMMIT; # ํธ๋์ญ์
์ ์ปค๋ฐํฉ๋๋ค.
SELECT * FROM memo;
๋ชจ๋ ์ฟผ๋ฆฌ๊ฐ ์ ์ํ๋๋ฉด ์๊ตฌ์ ์ผ๋ก ๋ณ๊ฒฝ์ฌํญ์ ๋ฐ์ํ๊ฒ ๋๋ค.
JPA์ ํธ๋์ญ์
์์์ฑ ์ปจํ ์คํธ๋ฅผ entity ๊ฐ์ฒด๋ฅผ ์ ์ฅํ๋ค๊ณ ํด์ DB์ ๋ฐ๋ก ๋ฐ์๋์ง๋ ์๋๋ค.
์์์ DB์ ํธ๋์ญ์ ์ฒ๋ผ JPA์์๋ ์์์ฑ ์ปจํ ์คํธ๋ก ๊ด๋ฆฌํ๊ณ ์๋ ๋ณ๊ฒฝ์ด ๋ฐ์ํ Entity ๊ฐ์ฒด์ ์ ๋ณด๋ฅผ ์ฐ๊ธฐ ์ง์ฐ ์ ์ฅ์์ ์ ๋ถ ๊ฐ๊ณ ์๋ค๊ฐ ๋ง์ง๋ง์ SQL์ ํ๋ฒ์ DB์ ์์ฒญํด ๋ณ๊ฒฝ์ ๋ฐ์ํ๋ค.
*EntityTransaction ์ฑ๊ณต ํ ์คํธ
@Test
@DisplayName("EntityTransaction ์ฑ๊ณต ํ
์คํธ")
void test1() {
EntityTransaction et = em.getTransaction(); // EntityManager ์์ EntityTransaction ์ ๊ฐ์ ธ์ต๋๋ค.
et.begin(); // ํธ๋์ญ์
์ ์์ํฉ๋๋ค.
try { // DB ์์
์ ์ํํฉ๋๋ค.
Memo memo = new Memo(); // ์ ์ฅํ Entity ๊ฐ์ฒด๋ฅผ ์์ฑํฉ๋๋ค.
memo.setId(1L); // ์๋ณ์ ๊ฐ์ ๋ฃ์ด์ค๋๋ค.
memo.setUsername("Robbie");
memo.setContents("์์์ฑ ์ปจํ
์คํธ์ ํธ๋์ญ์
์ดํดํ๊ธฐ");
em.persist(memo); // EntityManager ์ฌ์ฉํ์ฌ memo ๊ฐ์ฒด๋ฅผ ์์์ฑ ์ปจํ
์คํธ์ ์ ์ฅํฉ๋๋ค.
et.commit(); // ์ค๋ฅ๊ฐ ๋ฐ์ํ์ง ์๊ณ ์ ์์ ์ผ๋ก ์ํ๋์๋ค๋ฉด commit ์ ํธ์ถํฉ๋๋ค.
// commit ์ด ํธ์ถ๋๋ฉด์ DB ์ ์ํํ DB ์์
๋ค์ด ๋ฐ์๋ฉ๋๋ค.
} catch (Exception ex) {
ex.printStackTrace();
et.rollback(); // DB ์์
์ค ์ค๋ฅ ๋ฐ์ ์ rollback ์ ํธ์ถํฉ๋๋ค.
} finally {
em.close(); // ์ฌ์ฉํ EntityManager ๋ฅผ ์ข
๋ฃํฉ๋๋ค.
}
emf.close(); // ์ฌ์ฉํ EntityManagerFactory ๋ฅผ ์ข
๋ฃํฉ๋๋ค.
}
- @Entityํด๋์ค์์ Setter ์ฌ์ฉ์ ์ฃผ์์ฌํญ:
Setter๋ ์ด๋ฏธ ์์ฑ์ด ๋ ๊ฐ์ฒด์ ๋ฐ์ดํฐ๋ฅผ ์์ ํ ์ ์๋ ๋ฐฉ๋ฒ์ด๋ค.
Entity๋ DB์ ๋งคํ์ด ๋๋ ๊ฒ์ด๋ผ ๊ณ ๋ฏผํ๊ณ ํ์ํ ๋ถ๋ถ์๋ง ์ฌ์ฉํด์ผ ํ๋ค. (๋ง์ฝ setter์ ๋ฐ์ดํฐ๋ฅผ ๋ณ๊ฒฝํด db์ ๋ฐ์๋๋ฉด ์๋๋ค.)
์์์ฑ ์ปจํ์คํธ์ ๊ธฐ๋ฅ
# 1์ฐจ ์บ์
- ์์์ฑ ์ปจํ์คํธ๋ ๋ด๋ถ์ ์ผ๋ก ์บ์๋ฅผ ๊ฐ๊ณ ์๋ค. ์ฐ๋ฆฌ๊ฐ ์ ์ฅํ๋ Entity ๊ฐ์ฒด๊ฐ 1์ฐจ ์บ์(์บ์์ ์ฅ์)์ ์ ์ฅ๋๋ค.
- ์บ์์ ์ฅ์๋ ์ด๋ ๊ฒ Map ์๋ฃ๊ตฌ์กฐ ํํ๋ก ๋์ด์๋ค.
- key์๋@Id๋ก ๋งคํํ ๊ธฐ๋ณธ ํค ์ฆ, ์๋ณ์ ๊ฐ์ ์ ์ฅํ๋ค. value์๋ ํด๋น Entityํด๋์ค์ ๊ฐ์ฒด๋ฅผ ์ ์ฅํ๋ค.
- ์์์ฑ ์ปจํ ์คํธ๋ ์บ์ ์ ์ฅ์ key์ ์ ์ฅํ ์๋ณ์๊ฐ์ ์ฌ์ฉํ์ฌ Entity ๊ฐ์ฒด๋ฅผ ๊ตฌ๋ถํ๊ณ ๊ด๋ฆฌํ๋ค.
1์ฐจ ์บ์ ๊ธฐ๋ฅ์ผ๋ก DB์กฐํ ํ์๋ฅผ ์ค์ฌ์ฃผ๋ฉฐ DB row ํ๋๋น ๊ฐ์ฒด 1๊ฐ๊ฐ ์ฌ์ฉ๋๋ ๊ฒ์ ๋ณด์ฅํ๋ค.(๊ฐ์ฒด ๋์ผ์ฑ ๋ณด์ฅ)
#์ฐ๊ธฐ ์ง์ฐ ์ ์ฅ์
JPA ๊ฐ ํธ๋์ญ์ ์ฒ๋ผ SQL์ ๋ชจ์ DB์ ํ๋ฒ์ ๋ฐ์ํ๋ค๊ณ ํ๋ค.
์ด๋ฅผ ๊ตฌํํ๊ธฐ ์ํด ์ฐ๊ธฐ์ง์ฐ์ ์ฅ์๋ฅผ ๋ง๋ค์ด SQL์ ๋ชจ์๋๊ณ ์๋ค๊ฐ ํธ๋์ญ์ commit ํ์ DB์ ๋ฐ์ํ๋ค.
+flush()
- ํธ๋์ญ์ commit ํ ์ฐ๊ธฐ ์ง์ฐ ์ ์ฅ์์ SQL์ด ํ๋ฒ์ ์์ฒญ๋๋ค.
- commitํ์ ์ถ๊ฐ์ ์ธ ๋์์ด ํ๋ ์๋ค. em.flush() ๋ฉ์๋์ ํธ์ถ์ด๋ค.
ํด๋น ๋ฉ์๋๋ ์์์ฑ ์ปจํ ์คํธ์ ๋ณ๊ฒฝ๋ด์ฉ์ DB์ ๋ฐ์ํ๋ ์ญํ ์ ์ํํ๋ค. (์ฐ๊ธฐ ์ง์ฐ ์ ์ฅ์์ SQL์ DB์ ์์ฒญํ๋ ์ญํ ์ ์ํ.)
# Insert, Delete, Update ๋ฑ ๋ฐ์ดํฐ ๋ณ๊ฒฝ SQL์ DB์ ์์ฒญํ๊ธฐ ์ํด์๋ ํธ๋์ญ์ ํ๊ฒฝ์ ์์ด์ผํ๋ค. ์๋ ์ค๋ฅ ๋ฐ์ํจ.
- JPA์์ Update๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ.
loaded state : ์ต์ด ์ํ์ ํ์ฌ ์ํ๋ฅผ ๋น๊ตํ๊ณ ๋ณ๊ฒฝ์ด ์๋ค๋ฉด Update SQL์ ์์ฑํ์ฌ ์ฐ๊ธฐ ์ง์ฐ ์ ์ฅ์์ ์ ์ฅ ํ DB๋ฅผ ์์ฒญํ๋ค.
(๋ณ๊ฒฝ์ ์ํ๋ฉด ์ฐ์ ์กฐํ)
Entity์ ์ํ
- ๋น์์
- ๋น์์ ์ํ์์๋ JPA์ ์ํด ๊ด๋ฆฌ๋์ง ์๊ธฐ ๋๋ฌธ์ ํด๋น ๊ฐ์ฒด์ ๋ฐ์ดํฐ๋ฅผ ๋ณ๊ฒฝํด๋ ๋ณ๊ฒฝ ๊ฐ์ง๊ฐ ์ด๋ฃจ์ด์ง์ง ์๋๋ค.
Memo memo = new Memo(); // ๋น์์ ์ํ
memo.setId(1L);
memo.setUsername("Robbie");
memo.setContents("๋น์์๊ณผ ์์ ์ํ");
- ์์ ์ํ
em.persist(memo);
ํด๋น ๋ฉ์๋๋ฅผ ํตํด ์์์ฑ ์ปจํ ์คํธ์ ์ ์ฅ๋์๊ณ ์ด์ JPA์ ์ํด ๊ด๋ฆฌ๋๋ ์์์ํ์ entity๊ฐ ๋์๋ค.
'Spring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
TIL Spring #3-1 (0) | 2023.12.14 |
---|---|
TIL Spring #2-5 (0) | 2023.12.13 |
TIL Spring #2-3 (0) | 2023.12.12 |
TIL Spring 2-2 (0) | 2023.12.08 |
TIL Spring 2-1 (1) | 2023.12.07 |