์ผ | ์ | ํ | ์ | ๋ชฉ | ๊ธ | ํ |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
- ๋์ ํฉ
- ์ด๋ถ ํ์
- ๋ฌธ์์ด
- error
- ๋งต
- ๋ถํ ์ ๋ณต
- BFS
- Spring
- OS
- ๊ตฌํ
- DP
- GCP
- CVE
- dfs
- ์๋ฎฌ๋ ์ด์
- java
- Reversing
- ๋ฐ์ดํฌ์คํธ๋ผ
- thymeleaf
- ์ฐ์ ์์ ํ
- ์์ ์ ๋ ฌ
- JPA
- c++
- web
- ์คํ
- ์ต๋จ ๊ฒฝ๋ก
- ๊ทธ๋ฆฌ๋
- ์ฌ๊ท
- dynamic debugging
- ๋ฐฑํธ๋ํน
- Today
- Total
hades
[JPA] JPA ๊ธฐ์ด ๋ณธ๋ฌธ
JPA ์๊ฐ
JPA
- Java Persistnce API
- Java ์ง์์ ORM ํ์ค
ORM
- Object-relational mapping (๊ฐ์ฒด ๊ด๊ณ ๋งคํ)
- ๊ฐ์ฒด๋ ๊ฐ์ฒด๋๋ก ์ค๊ณํ๊ณ , ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋๋ก ์ค๊ณํ๊ณ , ORM ํ๋ ์์ํฌ๊ฐ ๊ฐ์ฒด์ ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ค๊ฐ์์ ๋งคํ
- ๋์ค์ ์ธ ์ธ์ด์๋ ๋๋ถ๋ถ ORM ๊ธฐ์ ์ด ์กด์ฌ
JPA๋ ์ ํ๋ฆฌ์ผ์ด์ ๊ณผ JDBC ์ฌ์ด์์ ๋์
์ฐธ๊ณ ) JDBC(Java Database Connectivity)๋ ์๋ฐ์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ํ ์ ์๋๋ก ํ๋ ์๋ฐ API์ด๋ค.
ํธ๋์ญ์ (Transaction)์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ํ๋ฅผ ๋ณํ์ํค๊ธฐ ํด์ ์ํํ๋ ์์ ์ ๋จ์์ด๋ค. ํ๋์ ์ฟผ๋ฆฌ๋ฌธ์ด ์๋๋ค.
JPA ๋์ - ์ ์ฅ
persist๋ฅผ ํ๋ค๋ฉด, MemberDAO(EntityManager)๊ฐ Entity Object๋ฅผ JPA์ ์ ๋ฌํ๊ณ , Entity Object๋ JPA๊ฐ ์์์ ๋ถ์ํ๊ณ , INSERT๊น์ง ํด์ค๋ค.
์ฐธ๊ณ ) DAO๋ Data Access Object๋ก DB์ ์ ๊ทผํ๋ ์ญํ ์ ํ๋ ๊ฐ์ฒด๋ฅผ ์๋ฏธํ๋ค.
JPA ๋์ - ์กฐํ
MemberDAO(EntityManager)๊ฐ JPA์๊ฒ id๋ฅผ ๋๊ธฐ๋ฉด, JPA๊ฐ SELECT ํด์ Entity Object๋ฅผ ๋ฐํํ๋ค.
JPA๋ ํ์ค ๋ช ์ธ
์ฐ๋ฆฌ๋ JPA๋ผ๋ ํ์ค ์ธํฐํ์ด์ค์ Hibernate๋ผ๋ ๊ตฌํ์ฒด๋ฅผ ์ด๋ค.
JPA์ CRUD
- ์ ์ฅ: em.persist(member)
- ์กฐํ: Member member = em.find(Member.class, memberId)
- ์์ : member.setName(“๋ณ๊ฒฝํ ์ด๋ฆ”)
- ์ญ์ : em.remove(member)
JPA์ ์ฑ๋ฅ ์ต์ ํ ๊ธฐ๋ฅ
JPA๊ฐ ์ค๊ฐ์ ์๊ธฐ ๋๋ฌธ์ ๊ฐ๋ฅํ ์ผ๋ค์ด๋ค.
1์ฐจ ์บ์์ ๋์ผ์ฑ(identity) ๋ณด์ฅ
String memberId = "100";
Member m1 = jpa.find(Member.class, memberId); //SQL
Member m2 = jpa.find(Member.class, memberId); //์บ์
println(m1 == m2) //true
ํธ๋์ญ์ ์ ์ง์ํ๋ ์ฐ๊ธฐ ์ง์ฐ - INSERT
1. ํธ๋์ญ์
์ ์ปค๋ฐํ ๋๊น์ง INSERT SQL์ ๋ชจ์์ ์ ์ฅ
2. JDBC BATCH SQL ๊ธฐ๋ฅ์ ์ฌ์ฉํด์ ํ๋ฒ์ SQL ์ ์ก
transaction.begin(); // [ํธ๋์ญ์
] ์์
em.persist(memberA);
em.persist(memberB);
em.persist(memberC);
//์ฌ๊ธฐ๊น์ง INSERT SQL์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ณด๋ด์ง ์๋๋ค.
//์ปค๋ฐํ๋ ์๊ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ INSERT SQL์ ๋ชจ์์ ๋ณด๋ธ๋ค.
transaction.commit(); // [ํธ๋์ญ์
] ์ปค๋ฐ
์ง์ฐ ๋ก๋ฉ(Lazy Loading)
JPA ์์
JPA ๊ตฌ๋ ๋ฐฉ์
์์์ฑ ๊ด๋ฆฌ - ๋ด๋ถ ๋์ ๋ฐฉ์
์์์ฑ ์ปจํ ์คํธ
- ์ํฐํฐ๋ฅผ ์๊ตฌ ์ ์ฅํ๋ ํ๊ฒฝ์ด๋ผ๋ ์๋ฏธ์ด๋ค.
- em.persist(entity)๋ entity๋ฅผ DB๊ฐ ์๋๋ผ ์์์ฑ ์ปจํ ์คํธ์ ์ ์ฅํ๋ ๊ฒ์ด๋ค.
- ์์์ฑ ์ปจํ ์คํธ๋ ๋ ผ๋ฆฌ์ ์ธ ๊ฐ๋ ์ด๋ค.
- ์ํฐํฐ ๋งค๋์ ๋ฅผ ํตํด์ ์์์ฑ ์ปจํ ์คํธ์ ์ ๊ทผํ๋ค.
์ํฐํฐ์ ์๋ช ์ฃผ๊ธฐ
- ๋น์์ (new/transient) : ์์์ฑ ์ปจํ ์คํธ์ ์ ํ ๊ด๊ณ๊ฐ ์๋ ์๋ก์ด ์ํ, JPA์ ๊ด๊ณ๊ฐ ์๋ ์ํ์ด๋ค.
- ์์ (managed) : ์์์ฑ ์ปจํ ์คํธ์ ๊ด๋ฆฌ๋๋ ์ํ
- ์ค์์ (detached) : ์์์ฑ ์ปจํ ์คํธ์ ์ ์ฅ๋์๋ค๊ฐ ๋ถ๋ฆฌ๋ ์ํ
- ์ญ์ (removed) : ์ญ์ ๋ ์ํ
๋น์์
// ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ธฐ๋ง ํ ์ํ(๋น์์)
Member member = new Member();
member.setId("member1");
member.setUsername("ํ์1");
์์
//๊ฐ์ฒด๋ฅผ ์์ฑํ ์ํ(๋น์์)
Member member = new Member();
member.setId("member1");
member.setUsername(“ํ์1”);
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
//๊ฐ์ฒด๋ฅผ ์์์ฑ ์ปจํ
์คํธ์ ์ ์ฅํ ์ํ(์์)
em.persist(member);
em.persist(member)๋ฅผ ํ์ ๋ DB์ ์ฟผ๋ฆฌ๊ฐ ๋ ๋ผ๊ฐ๋๊ฒ ์๋๋ผ, ํธ๋์ญ์ ์ด ์ปค๋ฐ๋ ๋ ์ฟผ๋ฆฌ๊ฐ ๋ ๋ผ๊ฐ๋ค.
์ค์์
//์์์ฑ ์ปจํ
์คํธ์ ์๋ ์ํฐํฐ๋ฅผ ๋ถ๋ฆฌํ ์ํ(์ค์์)
em.detach(member);
์ญ์
//๊ฐ์ฒด๋ฅผ ์ญ์ ํ ์ํ(์ญ์ )
em.remove(member);
์์์ฑ ์ปจํ ์คํธ์ ์ด์
์ํฐํฐ ์กฐํ, 1์ฐจ ์บ์
//์ํฐํฐ๋ฅผ ์์ฑํ ์ํ(๋น์์)
Member member = new Member();
member.setId("member1");
member.setUsername("ํ์1");
//์ํฐํฐ๋ฅผ ์์
em.persist(member);
EntityManager๋ก ์์์ฑ ์ปจํ ์คํธ์ ์ ๊ทผํ์ง๋ง, ์์์ ์ผ๋ก ๊ฐ๋ค๊ณ ์ทจ๊ธํ๋ค.
1์ฐจ ์บ์์ ์๋ Entity๋ฅผ ์กฐํํ๋ ๊ฒฝ์ฐ
Member member = new Member();
member.setId("member1");
member.setUsername("ํ์1");
//1์ฐจ ์บ์์ ์ ์ฅ๋จ
em.persist(member);
//1์ฐจ ์บ์์์ ์กฐํ
Member findMember = em.find(Member.class, "member1");
์์์ฑ ์ปจํ ์คํธ์๋ 1์ฐจ ์บ์๊ฐ ์์ด์ find๋ฅผ ํ๋ฉด, 1์ฐจ ์บ์์์ ๋จผ์ ์กฐํํ๋ค.
1์ฐจ ์บ์์ ์๋ Entity๋ฅผ ์กฐํํ๋ ๊ฒฝ์ฐ
Member findMember2 = em.find(Member.class, "member2");
1์ฐจ ์บ์์ ์๋ ๊ฒฝ์ฐ์๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์กฐํํ๊ณ , ์์์ฑ ์ปจํ ์คํธ์ 1์ฐจ ์บ์์ ์ ์ฅํ๊ณ ๋ฐํํ๋ค.
๊ฐ์ ์ํฐํฐ๋ฅผ ์กฐํํ๋ ๊ฒฝ์ฐ, 1์ฐจ ์บ์์์ ์กฐํํ๋ฏ๋ก ์ฒซ๋ฒ์งธ ๊ฒฝ์ฐ์ ๋ฌ๋ฆฌ ์ฟผ๋ฆฌ๋ฌธ์ด ๋ ๋ผ๊ฐ์ง ์๋๋ค.
์ฐธ๊ณ ) 1์ฐจ ์บ์๋ ์ฌ์ฉ์ ํ๋(=ํธ๋์ญ์ ํ๋)์๋ง ์ฐ๊ด์ด ์๋ค.
์์์ฑ ์ํฐํฐ์ ๋์ผ์ฑ ๋ณด์ฅ
Member a = em.find(Member.class, "member1");
Member b = em.find(Member.class, "member1");
System.out.println(a == b); //๋์ผ์ฑ ๋น๊ต true
ํธ๋์ญ์ ์ ์ง์ํ๋ ์ฐ๊ธฐ ์ง์ฐ
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
//์ํฐํฐ ๋งค๋์ ๋ ๋ฐ์ดํฐ ๋ณ๊ฒฝ์ ํธ๋์ญ์
์ ์์ํด์ผ ํ๋ค.
transaction.begin(); // [ํธ๋์ญ์
] ์์
em.persist(memberA);
em.persist(memberB);
//์ฌ๊ธฐ๊น์ง INSERT SQL์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ณด๋ด์ง ์๋๋ค.
//์ปค๋ฐํ๋ ์๊ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ INSERT SQL์ ๋ณด๋ธ๋ค.
transaction.commit(); // [ํธ๋์ญ์
] ์ปค๋ฐ
em.persist๋ฅผ ํ๋ฉด, 1์ฐจ ์บ์์ ์ํฐํฐ๋ฅผ ์ ์ฅํ ๋ฟ๋ง ์๋๋ผ, INSERT SQL์ ์์ฑํ์ฌ ์ฐ๊ธฐ ์ง์ฐ SQL ์ ์ฅ์์ ์ ์ฅํ๋ค. ๊ทธ ํ, transaction.commit()์ด ์ผ์ด๋ ๊ฒฝ์ฐ์ DB๋ก ์ฟผ๋ฆฌ๋ฌธ์ ๋ ๋ฆฐ๋ค. ๋งค๋ฒ DB๋ก ์ฟผ๋ฆฌ๋ฌธ์ ๋ ๋ฆฌ์ง ์์ผ๋ฏ๋ก ์ต์ ํ์ ์ฅ์ ์ด ์๋ค.
์ํฐํฐ ์์ - ๋ณ๊ฒฝ ๊ฐ์ง = ๋ํฐ ์ฒดํน
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin(); // [ํธ๋์ญ์
] ์์
// ์์ ์ํฐํฐ ์กฐํ
Member memberA = em.find(Member.class, "memberA");
// ์์ ์ํฐํฐ ๋ฐ์ดํฐ ์์
memberA.setUsername("hi");
memberA.setAge(10);
//em.update(member) ๋๋ em.persist(member)๊ฐ ์์ด๋ ๋ณ๊ฒฝ๋ด์ฉ์ด ๋ฐ์๋จ
transaction.commit(); // [ํธ๋์ญ์
] ์ปค๋ฐ
JPA๋ commit์ด ํธ์ถ๋๋ฉด, flush()๊ฐ ํธ์ถ๋๊ณ , ์ํฐํฐ์ ์ค๋ ์ท์ ๋น๊ตํ๋ค. ๋น๊ตํ ๋ด์ฉ์ ๋ฐํ์ผ๋ก UPDATE ์ฟผ๋ฆฌ๋ฌธ์ ์ฐ๊ธฐ ์ง์ฐ SQL ์ ์ฅ์์ ์ ์ฅํ๋ค. ์ฐ๊ธฐ ์ง์ฐ SQL ์ ์ฅ์์ ์๋ ์ฟผ๋ฆฌ๋ค์ flushํ๊ณ , commitํ๋ค.
์ฐธ๊ณ ) ์ค๋ ์ท์ ์ฝ์ด์จ ์์ ์ ์ํ๋ฅผ ์๋ฏธํ๋ค.
ํ๋ฌ์
- ์์์ฑ ์ปจํ ์คํธ์ ๋ณ๊ฒฝ ๋ด์ฉ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฐ์ํ๋ ๊ฒ์ด๋ค.
- ํ๋ฌ์๊ฐ ๋ฐ์ํ๋ฉด ๋ณ๊ฒฝ ๊ฐ์ง๊ฐ ์ผ์ด๋๊ณ , ์ํฐํฐ ์์ ์ฟผ๋ฆฌ๋ฅผ ์ฐ๊ธฐ ์ง์ฐ SQL ์ ์ฅ์์ ๋ฑ๋กํ๊ณ , ์ฐ๊ธฐ ์ง์ฐ SQL ์ ์ฅ์์ ์ฟผ๋ฆฌ๋ฅผ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์กํ๋ค.
- ํ๋ฌ์๋ฅผ ํ๋๋ผ๋ 1์ฐจ ์บ์์๋ ๋ณํจ์ด ์๋ค. ์ฆ, 1์ฐจ ์บ์์ ์๋ ๊ฒ์ด ์ฌ๋ผ์ง์ง ์๋๋ค๋ ์๋ฏธ์ด๋ค.
- ํธ๋์ญ์ ์ด๋ผ๋ ์์ ๋จ์๊ฐ ์ค์ํ๊ธฐ ๋๋ฌธ์ ์ปค๋ฐ ์ง์ ์๋ง ํ๋ฌ์ํ๋ฉด ๋๋ค. ์ปค๋ฐํ๋ฉด ์๋์ผ๋ก ํ๋ฌ์๋๋ค.
์ฐธ๊ณ ) flush๋ ์ฟผ๋ฆฌ๋ฅผ ์ ์กํ๋ ์ญํ ์ด๊ณ commit์ ๋ด๋ถ์ ์ผ๋ก flush๋ฅผ ์ํํ ๋ค ํธ๋์ญ์ ์ ๋๋ด๋ ์ญํ
์์์ฑ ์ปจํ ์คํธ๋ฅผ ํ๋ฌ์ํ๋ ๋ฐฉ๋ฒ
- em.flush() - ์ง์ ํธ์ถ
- ํธ๋์ญ์ ์ปค๋ฐ - ํ๋ฌ์ ์๋ ํธ์ถ
- JPQL ์ฟผ๋ฆฌ ์คํ - ํ๋ฌ์ ์๋ ํธ์ถ
์ค์์ ์ํ๋ก ๋ง๋๋ ๋ฐฉ๋ฒ
- em.detach(entity) : ํน์ ์ํฐํฐ๋ง ์ค์์ ์ํ๋ก ์ ํ
- em.clear() : ์์์ฑ ์ปจํ ์คํธ๋ฅผ ์์ ํ ์ด๊ธฐํ
- em.close() : ์์์ฑ ์ปจํ ์คํธ๋ฅผ ์ข ๋ฃ
์ํฐํฐ ๋งคํ
๊ฐ์ฒด์ ํ ์ด๋ธ ๋งคํ
@Entity
- @Entity๊ฐ ๋ถ์ ํด๋์ค๋ JPA๊ฐ ๊ด๋ฆฌํ๋ ์ํฐํฐ์ด๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ํ ์ด๋ธ๊ณผ ๋งคํ๋๋ค.
- ํ๋ผ๋ฏธํฐ๊ฐ ์๋ public ๋๋ protected ๊ธฐ๋ณธ ์์ฑ์๊ฐ ํ์์ด๋ค.
- final, enum, interface, inner ํด๋์ค ์ฌ์ฉ ๋ถ๊ฐ
@Table
- @Table์ ์ํฐํฐ์ ๋งคํํ ํ ์ด๋ธ ์ง์
๋ฐ์ดํฐ๋ฒ ์ด์ค ์คํค๋ง ์๋ ์์ฑ
- DDL์ ์ ํ๋ฆฌ์ผ์ด์ ์คํ ์์ ์ ์๋ ์์ฑํ๋ ๊ธฐ๋ฅ์ด๋ค.
- ํ ์ด๋ธ์ ์ง์ ์ค์ ํ์ง ์์๋ ๋๋ฏ๋ก ๊ฐ์ฒด์ ์ง์คํ ์ ์๋ค.
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ฐฉ์ธ์ ํ์ฉํด์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ง๋ ์ ์ ํ DDL ์์ฑํ๋ค.
- ์ด๋ ๊ฒ ์์ฑ๋ DDL์ ๊ฐ๋ฐ ์ฅ๋น์์๋ง ์ฌ์ฉํด์ผ ํ๋ค. ์์ฑ๋ DDL์ ์ด์์๋ฒ์์๋ ์ฌ์ฉํ์ง ์๊ฑฐ๋, ์ ์ ํ ๋ค๋ฌ์ ํ ์ฌ์ฉํด์ผ ํ๋ค.
์ฐธ๊ณ ) DDL(Data Definition Language, ๋ฐ์ดํฐ ์ ์์ด)๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ตฌ์กฐ ์ ์์ ์ฌ์ฉํ๋ ์ธ์ด๋ก, ํ ์ด๋ธ์ด๋ ์ปฌ๋ผ ๋ฑ์ ์์ฑ, ์์ , ์ญ์ ํ๋ค.
์ฃผ์์ฌํญ
- ์ด์ ์ฅ๋น์๋ ์ ๋ create, create-drop, update ์ฌ์ฉํ๋ฉด ์๋๋ค.
- ๊ฐ๋ฐ ์ด๊ธฐ ๋จ๊ณ๋ create ๋๋ update
- ํ ์คํธ ์๋ฒ๋ update ๋๋ validate
- ์คํ ์ด์ง๊ณผ ์ด์ ์๋ฒ๋ validate ๋๋ none
DDL ์์ฑ ๊ธฐ๋ฅ
- @Column(nullable = false, length = 10) == ์ ์ฝ์กฐ๊ฑด ์ถ๊ฐ: ํ์, 10์ ์ด๊ณผX
- DDL ์์ฑ ๊ธฐ๋ฅ์ DDL์ ์๋ ์์ฑํ ๋๋ง ์ฌ์ฉ๋๊ณ , JPA์ ์คํ ๋ก์ง์๋ ์ํฅ์ ์ฃผ์ง ์๋๋ค.
ํ๋์ ์ปฌ๋ผ ๋งคํ
๋งคํ ์ ๋ ธํ ์ด์ ์ ๋ฆฌ
@Column
unique ๋์ @Table์์ uniqueConstraints๋ฅผ ์ฌ์ฉํ๋ค.
@Enumarated
USER, ADMIN๋ง ์๋ค๊ฐ ๋งจ ์์ GUEST๋ฅผ ์ถ๊ฐํ๋ ๊ฒฝ์ฐ, USER์ GUEST๊ฐ ๊ฐ๊ฒ ๋๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค. ๋ฐ๋ผ์, ๋ฌด์กฐ๊ฑด EnumType.STRING์ ์ฌ์ฉํด์ผ ํ๋ค.
@Temporal
๋ ์ง ํ์
(java.util.Date, java.util.Calendar)์ ๋งคํํ ๋ ์ฌ์ฉ
์ฐธ๊ณ ) LocalDate, LocalDateTime์ ์ฌ์ฉํ๋ฉด, ์ต์ ํ์ด๋ฒ๋ค์ดํธ ์์์ ๋ ์ง ํ์ ์ผ๋ก ๋งคํํด์ฃผ๊ธฐ ๋๋ฌธ์ @Temporal์ ์์ฆ์ ์ฐ์ง ์๋๋ค.
@Lob
- ๋ํ ์ค๋ธ์ ํธ์ ์ฌ์ฉํ๋ค.
- @Lob์๋ ์ง์ ํ ์ ์๋ ์์ฑ์ด ์๋ค.
- ๋งคํํ๋ ํ๋ ํ์ ์ด ๋ฌธ์๋ฉด ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ CLOB๊ณผ ๋งคํ๋๊ณ , ๋๋จธ์ง๋ BLOB ๋งคํ๋๋ค.
- CLOB: String, char[], java.sql.CLOB
- BLOB: byte[], java.sql. BLOB
๊ธฐ๋ณธ ํค ๋งคํ
์ง์ ํ ๋น
setId๋ฅผ ์ฌ์ฉํ์ฌ ์ํ๋ ๊ฐ์ผ๋ก ์ง์ ํ ๋น
์๋ ์์ฑ(@GeneratedValue)
- IDENTITY: ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋งก๊ธด๋ค. MySQL์์๋ ์ฃผ๋ก AUTO_INCREMENT๋ฅผ ์ฌ์ฉํ๋ค. IDENTITY์ ๋ฌธ์ ๋ id๊ฐ์ ์์ฑ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋งก๊ธฐ๊ธฐ ๋๋ฌธ์, em.persist๋ฅผ ํด์ 1์ฐจ ์บ์์ ์ ์ฅ์ ํ๋ ค๊ณ ํด๋ id๊ฐ์ ๋ชจ๋ฅธ๋ค. ๊ทธ๋์ ์์ธ์ ์ผ๋ก IDENTITY ๊ฒฝ์ฐ์๋ง em.persist๋ฅผ ํ ๋, ์ถ๊ฐ์ ์ผ๋ก flush๋ฅผ ํด์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์์ฑ๋ id ๊ฐ์ ๊ฐ์ง๊ณ 1์ฐจ ์บ์์ ์ ์ฅํ๋ค.
@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
...
}
System.out.println("=================");
em.persist(member);
System.out.println("=================");
- SEQUENCE: ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ํ์ค๋ฅผ ์ฌ์ฉํ๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ํ์ค๋ ์ ์ผํ ๊ฐ์ ์์๋๋ก ์์ฑํ๋ ํน๋ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค๋ธ์ ํธ์ด๋ค. @SequenceGenerator๊ฐ ํ์ํ๊ณ , generator๋ฅผ ๋งคํํ๋ค. ORACLE ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ฃผ๋ก ์ฌ์ฉํ๋ค.
@Entity
@SequenceGenerator(
name = "MEMBER_SEQ_GENERATOR",
sequenceName = "MEMBER_SEQ", //๋งคํํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ํ์ค ์ด๋ฆ
initialValue = 1, allocationSize = 1)
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "MEMBER_SEQ_GENERATOR")
private Long id;
...
}
SEQUENCE๋ ๋ง์ฐฌ๊ฐ์ง๋ก ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ํ์ค๋ฅผ ์ด์ฉํ๊ธฐ ๋๋ฌธ์ 1์ฐจ ์บ์์ ์ ์ฅํ๋ ค๊ณ ํ ๋ id๋ฅผ ๋ชจ๋ฅธ๋ค. flush๊น์ง ์๋๊ณ , ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ํ์ค์์ id๊ฐ๋ง ๋ฐ์์ค๊ณ 1์ฐจ ์บ์์ ์ ์ฅํ๋ค.
initialValue = 1, allocationSize = 50์ด๋ผ๋ฉด, ์์๋ฒํธ 50๊ฐ๋ฅผ ๋ฏธ๋ฆฌ ๋ฐ์์ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅ ํ ํ๋์ฉ ์ฌ์ฉํ๋ค.
์ฐธ๊ณ ) ddl-auto: create์์ ์ญ์ ๋๊ณ ์๋ก ์์ฑ๋๋ ๊ฒ์ ํ ์ด๋ธ์ด๋ค.
TABLE: ํค ์์ฑ์ฉ ํ ์ด๋ธ ์ฌ์ฉ, ๋ชจ๋ DB์์ ์ฌ์ฉ, @TableGenerator ํ์- AUTO: ๋ฐฉ์ธ์ ๋ฐ๋ผ ์๋ ์ง์ , ๊ธฐ๋ณธ๊ฐ
๊ถ์ฅํ๋ ์๋ณ์ ์ ๋ต
- ๊ธฐ๋ณธ ํค ์ ์ฝ ์กฐ๊ฑด: null์ด ์๋์ด์ผ ํจ, ์ ์ผ, ๋ณํ๋ฉด ์๋๋ค.
- ๋ฏธ๋๊น์ง ์ด ์กฐ๊ฑด์ ๋ง์กฑํ๋ ์์ฐํค๋ ์ฐพ๊ธฐ ์ด๋ ต๋ค. ๋๋ฆฌํค(๋์ฒดํค)๋ฅผ ์ฌ์ฉํ์.
- ์๋ฅผ ๋ค์ด ์ฃผ๋ฏผ๋ฑ๋ก๋ฒํธ๋ ๊ธฐ๋ณธ ํค๋ก ์ ์ ํ๊ธฐ ์๋ค.
- ๊ถ์ฅ: ํ์ ์ Longํ + ๋์ฒดํค + ํค ์์ฑ์ ๋ต ์ฌ์ฉ
๊ฒฐ๋ก ์ Auto Increment, ์ํ์ค ์ค๋ธ์ ํธ, uuid ์ฌ์ฉ ๊ถ์ฅ
์ค์ ์์ 1 - ์๊ตฌ์ฌํญ ๋ถ์๊ณผ ๊ธฐ๋ณธ ๋งคํ
๋๋ฉ์ธ ๋ชจ๋ธ ๋ถ์
- ํ์๊ณผ ์ฃผ๋ฌธ์ ๊ด๊ณ : ํ ํ์์ ์ฌ๋ฌ ๊ฐ์ ์ฃผ๋ฌธ์ ํ ์ ์๋ค. (์ผ๋๋ค)
- ์ฃผ๋ฌธ๊ณผ ์ํ์ ๊ด๊ณ : ํ ์ฃผ๋ฌธ์๋ ์ฌ๋ฌ ๊ฐ์ ์ํ์ด ํฌํจ๋ ์ ์๋ค. ํ ์ํ์ ์ฌ๋ฌ ์ฃผ๋ฌธ์ ํฌํจ๋ ์ ์๋ค. (๋ค๋๋ค) ์ธ๋ฐ, ์ฃผ๋ฌธ์ํ์ด๋ผ๋ ๊ฒ์ ๋์ ํ์ฌ ์ผ๋๋ค, ๋ค๋์ผ๋ก ํ์ด๋ธ๋ค.
์ํฐํฐ ์ค๊ณ
ํ ์ด๋ธ ์ค๊ณ
ํ ์ด๋ธ์ ์ธ๋ํค๋ฅผ ๊ฐ์ฒด์ ๊ทธ๋๋ก ๊ฐ์ ธ์ค๋ ๊ฒ์ ์ข์ ๊ฐ์ฒด ์งํฅ ์ค๊ณ ๋ฐฉ๋ฒ์ด ์๋๋ค. ๊ฐ์ฒด์์ ๋ฐ๋ก ์ ๊ทผํ ์ ์๋ ๊ฒ์ด ์ข๋ค.
์ฐ๊ด๊ด๊ณ ๋งคํ ๊ธฐ์ด
์์ ์๋๋ฆฌ์ค
- ํ์๊ณผ ํ์ด ์๋ค.
- ํ์์ ํ๋์ ํ์๋ง ์์๋ ์ ์๋ค.
- ํ์๊ณผ ํ์ ๋ค๋์ผ ๊ด๊ณ๋ค.
๊ฐ์ฒด๋ฅผ ํ ์ด๋ธ์ ๋ง์ถ์ด ๋ชจ๋ธ๋ง (๊ฐ์ฒด ์ฐ๊ด๊ด๊ณ ์์)
ํ์๊ณผ ํ์ด ๋ค๋์ผ ๊ด๊ณ์ผ ๋, ํ์์ด ์ํ ํ์ ํ๋์ด๋ฏ๋ก, ํ์์, ๋ค์ ๋งํด์ ๋ค ์ชฝ์ ์ธ๋ํค๋ฅผ ๋๋ ๊ฒ์ด ์ณ๋ค.
Team team = new Team();
team.setName("๋ ์ ๋ง๋๋ฆฌ๋");
em.persist(team);
Member member = new Member();
member.setUsername("ํธ๋ ๋");
member.setTeamId(team.getId());
em.persist(member);
Member findMember = em.find(Member.class, member.getId());
Long findTeamId = findMember.getTeamId();
Team findTeam = em.find(Team.class, findTeamId);
๊ฐ์ฒด์ ์ธ๋ํค๋ฅผ ์ง์ ์ ์ฅํ๊ณ , ์ด๋ฅผ ์ด์ฉํ์ฌ ์กฐํํ๋ ๋ฐฉ๋ฒ์ ๊ฐ์ฒด ์งํฅ์ ์ธ ๋ฐฉ๋ฒ๋ ์๋๊ณ , ๋งค์ฐ ๋ฒ๊ฑฐ๋ก์์ง๋ค.
๋จ๋ฐฉํฅ ์ฐ๊ด๊ด๊ณ
๊ฐ์ฒด ์งํฅ ๋ชจ๋ธ๋ง (๊ฐ์ฒด ์ฐ๊ด๊ด๊ณ ์ฌ์ฉ)
@Entity
public class Member {
@Id
@GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String username;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TEAM_ID")
private Team team;
...
}
Team team = new Team();
team.setName("๋ก์๋ง์๋ฐฉ๋ฒ๋");
em.persist(team); // TEAM_ID๋ฅผ ์ป์ ์ํ
Member member = new Member();
member.setUsername("์ ์งฑ๊ตฌ");
member.setTeam(team); // MEMBER์ TEAM_ID์ team์ id๋ฅผ ์ธ๋ํค๋ก ์ ์ฅ
em.persist(member); // MEMBER_ID๋ฅผ ์ป์ ์ํ
Member findMember = em.find(Member.class, member.getId());
System.out.println(findMember.getTeam().getName());
tx.commit();
Member์ team์ ์ง์ ํ๋ฉด TEAM์ TEAM_ID์ ๋ฐ๋ก ๋งคํ๋๋ ๊ฒ์ด ์๋๋ค. MEMBER์ TEAM_ID์ ๋งคํ๋๊ณ , ๊ทธ TEAM_ID๊ฐ TEAM์ TEAM_ID์ ๋งคํ๋๋ค.
Member์ team์ ๋ฐ๊พธ๋ฉด, ๊ทธ team์ TEAM_ID๋ก MEMBER์ TEAM_ID (FK)๊ฐ ๋ณ๊ฒฝ๋๋ค.
์๋ฐฉํฅ ์ฐ๊ด๊ด๊ณ์ ์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ
์๋ฐฉํฅ ์ฐ๊ด๊ด๊ณ์ mappedBy
Member์์ team์ ๋ฐ๊พธ๋ ๊ฒฝ์ฐ, MEMBER ํ ์ด๋ธ์์๋ ํค ๊ฐ๋ง ๋ณ๊ฒฝํ๋ฉด ๋์ง๋ง, ๊ฐ์ฒด์์๋ Member์์ team์ ๋ฐ๊พผ๋ค๊ณ ํด์ Team์ members๊ฐ ๋ณํํ์ง ์๋๋ค. ์ถ๊ฐ ์ค์ ์ด ํ์ํ๋ค. ์ด ์ถ๊ฐ ์ค์ ์ด mappedBy์ด๋ค.
@Entity
public class Team {
@Id
@GeneratedValue
@Column(name = "TEAM_ID")
private Long id;
private String name;
@OneToMany(mappedBy = "team") // Member์์ ๋งคํ๋ ๋ณ์๋ช
private List<Member> members = new ArrayList<>();
...
}
Team team = new Team();
team.setName("๋ก์๋ง์๋ฐฉ๋ฒ๋");
em.persist(team); // TEAM_ID๋ฅผ ์ป์ ์ํ
Member member = new Member();
member.setUsername("์ ์งฑ๊ตฌ");
member.setTeam(team); // MEMBER์ TEAM_ID์ team์ id๋ฅผ ์ธ๋ํค๋ก ์ ์ฅ
em.persist(member); // MEMBER_ID๋ฅผ ์ป์ ์ํ
em.flush();
em.clear();
Member findMember = em.find(Member.class, member.getId());
List<Member> members = findMember.getTeam().getMembers();
for (Member m : members) {
System.out.println("m = " + m.getUsername());
}
tx.commit();
๊ฐ์ฒด์ ํ ์ด๋ธ์ด ๊ด๊ณ๋ฅผ ๋งบ๋ ์ฐจ์ด
- ๊ฐ์ฒด ์ฐ๊ด๊ด๊ณ = 2๊ฐ : ํ์ -> ํ ์ฐ๊ด๊ด๊ณ 1๊ฐ(๋จ๋ฐฉํฅ), ํ -> ํ์ ์ฐ๊ด๊ด๊ณ 1๊ฐ(๋จ๋ฐฉํฅ)
- ํ ์ด๋ธ ์ฐ๊ด๊ด๊ณ = 1๊ฐ : ํ์ <-> ํ์ ์ฐ๊ด๊ด๊ณ 1๊ฐ(์๋ฐฉํฅ), MEMBER.TEAM_ID ์ธ๋ ํค ํ๋๋ก ์๋ฐฉํฅ ์ฐ๊ด๊ด๊ณ๋ฅผ ๊ฐ์ง๋ค. (์์ชฝ์ผ๋ก ์กฐ์ธํ ์ ์๋ค)
SELECT *
FROM MEMBER M
JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID
SELECT *
FROM TEAM T
JOIN MEMBER M ON T.TEAM_ID = M.TEAM_ID
์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ = ์๋ฐฉํฅ ๋งคํ ๊ท์น
- ๊ฐ์ฒด์ ๋ ๊ด๊ณ ์ค ํ๋๋ฅผ ์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ์ผ๋ก ์ง์
- ์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ๋ง์ด ์ธ๋ ํค๋ฅผ ๊ด๋ฆฌ(๋ฑ๋ก, ์์ )
- ์ฃผ์ธ์ด ์๋ ์ชฝ์ mappedBy ์์ฑ์ผ๋ก ์ฃผ์ธ์ ์ง์ ํ๊ณ , ์ฃผ์ธ์ด ์๋ ์ชฝ์ ์ฝ๊ธฐ๋ง ๊ฐ๋ฅํ๋ค.
- ์ธ๋ ํค๊ฐ ์๋ ๊ณณ, ๋ค ์ชฝ์ ๊ด๋ จ ๋ฉค๋ฒ๋ฅผ ์ฃผ์ธ์ผ๋ก ์ ํด๋ผ. ์ฌ๊ธฐ์๋ Member.team
์๋ฐฉํฅ ๋งคํ์ ๊ฐ์ฅ ๋ง์ด ํ๋ ์ค์ (์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ์ ๊ฐ์ ์ ๋ ฅํ์ง ์์)
์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ์ด ์๋ ์ชฝ์ ๊ฐ์ ๋ฃ์ผ๋ ค๊ณ ํ๋ฉด, ์ฐ๊ด๊ด๊ณ ์ฃผ์ธ์ด ์๋ ์ชฝ์ ์ฝ๊ธฐ ์ ์ฉ์ด๊ธฐ ๋๋ฌธ์ ๋ฐ์๋์ง ์๋๋ค.
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setName("member1");
//์ญ๋ฐฉํฅ(์ฃผ์ธ์ด ์๋ ๋ฐฉํฅ)๋ง ์ฐ๊ด๊ด๊ณ ์ค์
team.getMembers().add(member);
em.persist(member);
์์ํ ๊ฐ์ฒด ๊ด๊ณ๋ฅผ ๊ณ ๋ คํ๋ฉด, ์์ชฝ ๋ค ๊ฐ์ ์ ๋ ฅํ๋ ๊ฒ์ด ์ข๋ค
Team team = new Team();
team.setName("๋ก์๋ง์๋ฐฉ๋ฒ๋");
em.persist(team); // TEAM_ID๋ฅผ ์ป์ ์ํ
Member member = new Member();
member.setUsername("์ ์งฑ๊ตฌ");
member.setTeam(team); // MEMBER์ TEAM_ID์ team์ id๋ฅผ ์ธ๋ํค๋ก ์ ์ฅ
team.getMembers().add(member);
em.persist(member); // MEMBER_ID๋ฅผ ์ป์ ์ํ
//em.flush();
//em.clear();
Member findMember = em.find(Member.class, member.getId());
List<Member> members = findMember.getTeam().getMembers();
- ์ค๊ฐ์ em.flush()๋ฅผ ํ์ง ์์ ๊ฒฝ์ฐ, 1์ฐจ ์บ์์์๋ ์ฐ๊ด๊ด๊ณ ๋งคํ์ด ์๋ฒฝํ๊ฒ ์ด๋ฃจ์ด์ง์ง ์์์ผ๋ฏ๋ก, em.find()๋ก 1์ฐจ ์บ์์์ ํธ์ถํ ๋, Team์๋ member๋ค์ด ์๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค. em.find๋ก ์๋ก ๋ฐ์์์ผ ํ๋ค.
- ์ฐ๊ด๊ด๊ณ ๋ฉ์๋๋ฅผ ์์ฑํ๋ ๊ฒ์ด ์ข๋ค. Setter์ ๊ตฌ๋ณํ๊ธฐ ์ํด ์ด๋ฆ์์ change, add ๋ฑ์ ์ฌ์ฉํ๋ค.
public void changeTeam(Team team) {
this.team = team;
team.getMembers().add(this);
}
- ์๋ฐฉํฅ ๋งคํ์์ ๋ฌดํ ๋ฃจํ๋ฅผ ์กฐ์ฌํ์.
- toString() (= ๊ฐ์ฒด๋ฅผ toString ํ์์ผ๋ก ์ถ๋ ฅํจ) + lombok -> toString์์ ์ฐ๊ด๊ด๊ณ์ ์๋ ํ๋๋ค ์ ๊ฑฐ
- JSON ์์ฑ ๋ผ์ด๋ธ๋ฌ๋ฆฌ -> @Controller์์ ์ํฐํฐ๋ฅผ ์ง์ ๋ฐํํ์ง ์๊ณ , DTO๋ก ๋ณ๊ฒฝํด์ ๋ฐํํ ๊ฒ
์๋ฐฉํฅ ๋งคํ ์ ๋ฆฌ
- ๋จ๋ฐฉํฅ ๋งคํ์ ์ฐ์ ์ ์ผ๋ก ์ ํ๊ณ , ์๋ฐฉํฅ์ ํ์ํ ๋(๋ฐ๋๋ฐฉํฅ์ผ๋ก ์กฐํ๊ฐ ํ์ํ ๋) ์ถ๊ฐํด๋ ๋จ(ํ ์ด๋ธ์๋ ์ํฅ์ด ์์)
- JPQL์์ ์ญ๋ฐฉํฅ์ผ๋ก ํ์ํ ์ผ์ด ๋ง์
์ค์ ์์ 2 - ์ฐ๊ด๊ด๊ณ ๋งคํ ์์
ํ ์ด๋ธ ๊ตฌ์กฐ
๊ฐ์ฒด ๊ตฌ์กฐ
(Member๋ Order๋ฅผ ์ฝ๊ธฐ๋ง ํ๊ธฐ ๋๋ฌธ์?) ์ค์ ๋ก๋ Member์ orders๋ฅผ ๋ฃ๋ ๊ฒ์ ์ข์ง ์๋ค. ORDERS์ Member์ ๋ํ FK๊ฐ ์์ผ๋ฏ๋ก, ์ฟผ๋ฆฌ๋ฌธ์ ํตํด orders๋ฅผ ๊ตฌํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
์ค์ ๋ก List๋ ์์ด๋ ๋๋ค. ๋จ๋ฐฉํฅ ์ฐ๊ด๊ด๊ณ๋ง ๋ง์กฑํด๋ ๋๋ค. ํธ๋ฆฌ๋ฅผ ์ํด ์ค์ ํด๋ ๊ฒ ๋ฟ์ด๋ค. ํ์ง๋ง, JPQL ์์ฑ์ ์ํด์ ์๋ฐฉํฅ์ ํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค.
Member
@Entity
public class Member {
@Id
@GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String name;
private String city;
private String street;
private String zipcode;
@OneToMany(mappedBy = "member")
private List<Order> orders = new ArrayList<>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getZipcode() {
return zipcode;
}
public void setZipcode(String zipcode) {
this.zipcode = zipcode;
}
public List<Order> getOrders() {
return orders;
}
public void setOrders(List<Order> orders) {
this.orders = orders;
}
}
Order
@Entity
@Table(name = "ORDERS")
public class Order {
@Id
@GeneratedValue
@Column(name = "ORDER_ID")
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "MEMBER_ID")
private Member member;
@OneToMany(mappedBy = "order")
private List<OrderItem> orderItems = new ArrayList<>();
private LocalDateTime orderDate;
@Enumerated(EnumType.STRING)
private OrderStatus status;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Member getMember() {
return member;
}
public void setMember(Member member) {
this.member = member;
member.getOrders().add(this);
}
public List<OrderItem> getOrderItems() {
return orderItems;
}
public LocalDateTime getOrderDate() {
return orderDate;
}
public void setOrderDate(LocalDateTime orderDate) {
this.orderDate = orderDate;
}
public OrderStatus getStatus() {
return status;
}
public void setStatus(OrderStatus status) {
this.status = status;
}
// ์ฐ๊ด๊ด๊ณ ๋ฉ์๋
public void addOrderItem(OrderItem orderItem){
orderItems.add(orderItem);
orderItem.setOrder(this);
}
}
OrderItem
@Entity
public class OrderItem {
@Id
@GeneratedValue
@Column(name = "ORDER_ITEM_ID")
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "ITEM_ID")
private Item item;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "ORDER_ID")
private Order order;
private int orderPrice;
private int count;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Item getItem() {
return item;
}
public void setItem(Item item) {
this.item = item;
}
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
public int getOrderPrice() {
return orderPrice;
}
public void setOrderPrice(int orderPrice) {
this.orderPrice = orderPrice;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
Item
@Entity
public class Item {
@Id
@GeneratedValue
@Column(name = "ITEM_ID")
private Long id;
private String name;
private int price;
private int stockQuantity;
}
๊ฒฐ๋ก ์ ๋จ๋ฐฉํฅ ์ฐ๊ด๊ด๊ณ๋ก ์์ฑํ๊ณ ํ์ํ๋ฉด ์๋ฐฉํฅ์ ์ถ๊ฐํ์.
๋ค์ํ ์ฐ๊ด๊ด๊ณ ๋งคํ
์ฐ๊ด๊ด๊ณ ๋งคํ ์ ๊ณ ๋ ค์ฌํญ 3๊ฐ์ง
- ๋ค์ค์ฑ : @ManyToOne, @OneToMany, @OneToOne,
@ManyToMany - ๋จ๋ฐฉํฅ, ์๋ฐฉํฅ : ํ ์ด๋ธ์ ์ธ๋ ํค ํ๋๋ก ์์ชฝ ์กฐ์ธ์ด ๊ฐ๋ฅํ๋ฏ๋ก ๋ฐฉํฅ์ด๋ผ๋ ๊ฐ๋ ์ด ์๋ค. ๊ฐ์ฒด๋ ์ฐธ์กฐ์ฉ ํ๋๊ฐ ์๋ ์ชฝ์ผ๋ก๋ง ์ฐธ์กฐ๊ฐ ๊ฐ๋ฅํ๋ฐ, ํ์ชฝ๋ง ์ฐธ์กฐํ๋ฉด ๋จ๋ฐฉํฅ, ์์ชฝ์ด ์๋ก ์ฐธ์กฐํ๋ฉด ์๋ฐฉํฅ(๋จ๋ฐฉํฅ 2๊ฐ)์ด๋ค.
- ์ฐ๊ด๊ด๊ณ ์ฃผ์ธ: ์ธ๋ ํค๋ฅผ ๊ด๋ฆฌํ๋ ์ฐธ์กฐ, ์ฃผ์ธ์ ๋ฐ๋ํธ์ ์ธ๋ ํค์ ์ํฅ์ ์ฃผ์ง ์๊ณ ์ฝ๊ธฐ๋ง ๊ฐ๋ฅํ๋ค.
๋ค๋์ผ [N:1]
๋ค๋์ผ ๋จ๋ฐฉํฅ
@Entity
public class Member {
...
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TEAM_ID")
private Team team;
...
}
๋ค๋์ผ ์๋ฐฉํฅ
@Entity
public class Member {
...
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TEAM_ID")
private Team team;
...
}
@Entity
public class Team {
...
@OneToMany(mappedBy = "team") // Member์์ ๋งคํ๋ ๋ณ์๋ช
private List<Member> members = new ArrayList<>();
...
}
team์์ member๋ฅผ ์ฐพ๋ ๋ก์ง์ด ๋ง์ ๋, ์ ์ฝ๋๋ฅผ ์ถ๊ฐํ์ฌ ์๋ฐฉํฅ ๊ด๊ณ ๋งคํ ์ค์ ํ๋ค.
์ผ๋๋ค [1:N]
์ฐ๊ด๊ด๊ณ ์ฃผ์ธ์ด ๋ค ์ชฝ์ด ์๋ ์ผ ์ชฝ์ ์๋ค๋ ์๋ฏธ์ด๋ค. ๋ค๋์ผ์ ์ฌ์ฉํ์.
์ผ๋์ผ [1:1]
- ์ผ๋์ผ ๊ด๊ณ๋ ๊ทธ ๋ฐ๋๋ ์ผ๋์ผ
- ์ฃผ ํ ์ด๋ธ์ด๋ ๋์ ํ ์ด๋ธ ์ค์ ์ธ๋ ํค๋ฅผ ์ ์ฅํ ๊ณณ ์ ํ ๊ฐ๋ฅ
- ์ธ๋ ํค์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ ๋ํฌ(UNI) ์ ์ฝ์กฐ๊ฑด ์ถ๊ฐ
์ฐธ๊ณ ) ์ฃผ ํ ์ด๋ธ์ ์ฃผ๋ก ์ ๊ทผํ๋ ํ ์ด๋ธ
์ผ๋์ผ: ์ฃผ ํ ์ด๋ธ์ ์ธ๋ ํค ๋จ๋ฐฉํฅ
@Entity
public class Member {
...
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "LOCKER_ID")
private Locker locker;
...
}
์ผ๋์ผ: ์ฃผ ํ ์ด๋ธ์ ์ธ๋ ํค ์๋ฐฉํฅ
@Entity
public class Member {
...
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "LOCKER_ID")
private Locker locker;
...
}
@Entity
public class Locker {
...
@OneToOne(fetch = FetchType.LAZY, mappedBy = "locker")
private Member member;
}
- ๋ค๋์ผ ์๋ฐฉํฅ ๋งคํ ์ฒ๋ผ ์ธ๋ ํค๊ฐ ์๋ ๊ณณ์ด ์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ
- ๋ฐ๋ํธ์ mappedBy ์ ์ฉ
์ธ๋ ํค ์์น์ ๋ฐ๋ฅธ ๋น๊ต
- ์ฃผ ํ
์ด๋ธ์ ์ธ๋ ํค
- ์ฃผ ๊ฐ์ฒด๊ฐ ๋์ ๊ฐ์ฒด์ ์ฐธ์กฐ๋ฅผ ๊ฐ์ง๋ ๊ฒ์ฒ๋ผ ์ฃผ ํ ์ด๋ธ์ ์ธ๋ ํค๋ฅผ ๋๊ณ ๋์ ํ ์ด๋ธ์ ์ฐพ์
- ๊ฐ์ฒด์งํฅ ๊ฐ๋ฐ์๋ค์ด ์ ํธ
- JPA ๋งคํ ํธ๋ฆฌ
- ์ฅ์ : ์ฃผ ํ ์ด๋ธ๋ง ์กฐํํด๋ ๋์ ํ ์ด๋ธ์ ๋ฐ์ดํฐ๊ฐ ์๋์ง ํ์ธ ๊ฐ๋ฅ
- ๋จ์ : ๊ฐ์ด ์์ผ๋ฉด ์ธ๋ ํค์ null ํ์ฉ
- ๋์ ํ
์ด๋ธ์ ์ธ๋ ํค
- ๋์ ํ ์ด๋ธ์ ์ธ๋ํค๊ฐ ์กด์ฌ
- ์ ํต์ ์ธ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ฐ๋ฐ์๊ฐ ์ ํธ
- ์ฅ์ : ์ฃผ ํ ์ด๋ธ๊ณผ ๋์ ํ ์ด๋ธ์ ์ผ๋์ผ์์ ์ผ๋๋ค ๊ด๊ณ๋ก ๋ณ๊ฒฝํ ๋ ํ ์ด๋ธ ๊ตฌ์กฐ ์ ์ง
- ๋จ์ : ๋์ ํ ์ด๋ธ์์ ๊ฐ์ ์ฐพ์์ผ ํจ. ํ๋ก์ ๊ธฐ๋ฅ์ ํ๊ณ๋ก ์ง์ฐ๋ก๋ฉ์ผ๋ก ์ค์ ํด๋ ํญ์ ์ฆ์ ๋ก๋ฉ๋จ
๋ค๋๋ค [N:N]
์ฐ๊ฒฐ ํ ์ด๋ธ์ ์ถ๊ฐํด์ ์ผ๋๋ค + ๋ค๋์ผ๋ก ๋ฐ๊พธ๋ ๊ฒ์ด ์ข๋ค.
@JoinColumn
์ธ๋ ํค๋ฅผ ๋งคํํ ๋ ์ฌ์ฉํ๋ค.
๊ณ ๊ธ ๋งคํ
์์๊ด๊ณ ๋งคํ
- ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ ์์ ๊ด๊ณ๊ฐ ์์
- ์ํผํ์ ์๋ธํ์ ๊ด๊ณ๋ผ๋ ๋ชจ๋ธ๋ง ๊ธฐ๋ฒ์ด ๊ฐ์ฒด ์์๊ณผ ์ ์ฌ
- ์์๊ด๊ณ ๋งคํ: ๊ฐ์ฒด์ ์์ ๊ตฌ์กฐ์ DB์ ์ํผํ์ ์๋ธํ์ ๊ด๊ณ๋ฅผ ๋งคํ
์ฃผ์ ์ ๋ ธํ ์ด์
- @Inheritance(strategy=InheritanceType.XXX)
- JOINED: ์กฐ์ธ ์ ๋ต
- SINGLE_TABLE: ๋จ์ผ ํ ์ด๋ธ ์ ๋ต
- TABLE_PER_CLASS: ๊ตฌํ ํด๋์ค๋ง๋ค ํ ์ด๋ธ ์ ๋ต
- @DiscriminatorColumn(name=“DTYPE”) : DB์์ ์์ ์ ๊ณ ๋ คํ์ฌ ๊ตฌ๋ถ ํ ์์ฑ
- @DiscriminatorValue(“XXX”) : DB์์ ์์ ์ ๊ณ ๋ คํ์ฌ ๊ตฌ๋ถํ ๋ ์ฌ์ฉํ ๊ฐ ์ง์
์กฐ์ธ ์ ๋ต
- ๊ฐ๊ฐ ํ ์ด๋ธ๋ก ๋ณํ
- ์ฅ์
- ํ ์ด๋ธ ์ ๊ทํ
- ์ธ๋ ํค ์ฐธ์กฐ ๋ฌด๊ฒฐ์ฑ ์ ์ฝ์กฐ๊ฑด ํ์ฉ ๊ฐ๋ฅ, ID๋ฅผ ์ด์ฉ ๊ฐ๋ฅ
- ์ ์ฅ๊ณต๊ฐ ํจ์จํ
- ๋จ์
- ์กฐํ์ ์กฐ์ธ์ ๋ง์ด ์ฌ์ฉํ์ฌ ์ฑ๋ฅ ์ ํ
- ์กฐํ ์ฟผ๋ฆฌ๊ฐ ๋ณต์กํฉ
- ๋ฐ์ดํฐ ์ ์ฅ์ INSERT SQL 2๋ฒ ํธ์ถ
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Item {
@Id
@GeneratedValue
private Long id;
private String name;
private int price;
}
ITEM, ALBUM, MOVIE, BOOK ํ ์ด๋ธ ๋ชจ๋ ์์ฑ๋๋ค.
๋จ์ผ ํ ์ด๋ธ ์ ๋ต
- ํ ํ ์ด๋ธ์ ๋ชจ๋ ์ ์ฅํ๊ณ , DTYPE์ผ๋ก ๊ตฌ๋ถ
- ์ฅ์
- ์กฐ์ธ์ด ํ์ ์์ผ๋ฏ๋ก ์ผ๋ฐ์ ์ผ๋ก ์กฐํ ์ฑ๋ฅ์ด ๋น ๋ฆ
- ์กฐํ ์ฟผ๋ฆฌ๊ฐ ๋จ์ํจ
- ๋จ์
- ์์ ์ํฐํฐ๊ฐ ๋งคํํ ์ปฌ๋ผ์ ๋ชจ๋ null ํ์ฉ
- ๋จ์ผ ํ ์ด๋ธ์ ๋ชจ๋ ๊ฒ์ ์ ์ฅํ๋ฏ๋ก ํ ์ด๋ธ์ด ์ปค์ง ์ ์๊ณ , ์ํฉ์ ๋ฐ๋ผ์ ์กฐํ ์ฑ๋ฅ์ด ์คํ๋ ค ๋๋ ค์ง ์ ์๋ค.
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn
public abstract class Item {
@Id
@GeneratedValue
private Long id;
private String name;
private int price;
}
ITEM ํ ์ด๋ธ๋ง ์์ฑ๋๋ค. @DiscriminatorColumn์ด ์์ด๋ ํ์ํ๊ธฐ ๋๋ฌธ์ ์๋์ผ๋ก ์์ฑ๋๋ค.
๊ตฌํ ํด๋์ค๋ง๋ค ํ ์ด๋ธ ์ ๋ต
์ฅ์ ์ด ์๋ค. ์ฌ์ฉํ๋ฉด ์๋๋ค.
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Item {
@Id
@GeneratedValue
private Long id;
private String name;
private int price;
}
ITEM์ด ์์ฑ๋์ง ์๊ณ , MOVIE, ALBUM, BOOK๋ง ์์ฑ๋๋ค.
Item.class๋ก findํ ๊ฒฝ์ฐ์ ์ธ ํ ์ด๋ธ์ ๋ชจ๋ ํ์ํด์ผ ํ๊ธฐ ๋๋ฌธ์ ์ฑ๋ฅ์ด ์ข์ง ์๋ค.
@MappedSuperclass
id, name ๊ฐ์ ๊ณตํต ๋งคํ ์ ๋ณด๊ฐ ํ์ํ ๋ ์ฌ์ฉ
public class Member extends BaseEntity{
- ์์๊ด๊ณ ๋งคํ๊ณผ ๊ด๋ จ์ด ์๋ค.
- ์ํฐํฐ๊ฐ ์๋๊ธฐ ๋๋ฌธ์ ํ ์ด๋ธ๊ณผ ๋งคํ๋์ง ์๋๋ค.
- ๋ถ๋ชจ ํด๋์ค๋ฅผ ์์ ๋ฐ๋ ์์ ํด๋์ค์ ๋งคํ ์ ๋ณด๋ง ์ ๊ณต๋๋ค.
- ์กฐํ, ๊ฒ์ ๋ถ๊ฐํ๋ค, ์๋ฅผ ๋ค์ด em.find(BaseEntity) ๋ถ๊ฐ๋ฅ
- ์ง์ ์์ฑํด์ ์ฌ์ฉํ ์ผ์ด ์์ผ๋ฏ๋ก ์ถ์ ํด๋์ค๋ก ์์ฑํ๋ ๊ฒ์ด ์ข๋ค.
- ์ฃผ๋ก ๋ฑ๋ก์ผ, ์์ ์ผ, ๋ฑ๋ก์, ์์ ์ ๊ฐ์ ์ ์ฒด ์ํฐํฐ์์ ๊ณตํต์ผ๋ก ์ ์ฉํ๋ ์ ๋ณด๋ฅผ ์ ๊ณตํ๊ธฐ ์ํด ์ฌ์ฉํ๋ค.
- @Entity ํด๋์ค๋ ์ํฐํฐ๋ @MappedSuperclass๋ก ์ง์ ํ ํด๋์ค๋ง ์์ ๊ฐ๋ฅํ๋ค.
ํ๋ก์์ ์ฐ๊ด๊ด๊ณ ๊ด๋ฆฌ
ํ๋ก์
- em.find() : 1์ฐจ ์บ์์ ์๋ ๊ฒฝ์ฐ, ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ํตํด์ ์ค์ ์ํฐํฐ ๊ฐ์ฒด ์กฐํ
- em.getReference() : 1์ฐจ ์บ์์ ์๋ ๊ฒฝ์ฐ, ๋ฐ์ดํฐ๋ฒ ์ด์ค ์กฐํ๋ฅผ ๋ฏธ๋ฃจ๋ ๊ฐ์ง(ํ๋ก์) ์ํฐํฐ ์กฐํ
ํ๋ก์ ํน์ง
- ์ค์ ํด๋์ค๋ฅผ ์์ ๋ฐ์์ ๋ง๋ค์ด์ง๊ณ , ์ค์ ํด๋์ค์ ๊ฒ ๋ชจ์์ด ๊ฐ๋ค.
- ์ด๋ก ์ ์ฌ์ฉํ๋ ์ ์ฅ์์๋ ์ง์ง ๊ฐ์ฒด์ธ์ง ํ๋ก์ ๊ฐ์ฒด์ธ์ง ๊ตฌ๋ถํ์ง ์๊ณ ์ฌ์ฉํ๋ฉด ๋๋ค.
- ํ๋ก์ ๊ฐ์ฒด๋ ์์์ฑ ์ปจํ ์คํธ๊ฐ ๊ด๋ฆฌํ๋ค.
- ํ๋ก์ ๊ฐ์ฒด๋ฅผ ํธ์ถํ๋ฉด ํ๋ก์ ๊ฐ์ฒด๋ ์ค์ ๊ฐ์ฒด์ ๋ฉ์๋๋ฅผ ํธ์ถํ๋ค.
- ํ๋ก์ ๊ฐ์ฒด๋ ์ฒ์ ์ฌ์ฉํ ๋, ํ๋ก์ ๊ฐ์ฒด๊ฐ ์ค์ ์ํฐํฐ๋ก ๋ฐ๋๋ ๊ฒ์ด ์๋๋ผ ์ฐธ์กฐ๊ฐ ์ ์ฅ๋๋ค.
- ํ๋ก์ ๊ฐ์ฒด๋ ์๋ณธ ์ํฐํฐ๋ฅผ ์์๋ฐ๋๋ฐ, ์์ ํ ๊ฐ์ ํ์ ์ ์๋๋ค. ๋ฐ๋ผ์ Class ์ฒดํฌ์ ์ฃผ์ํด์ผ ํ๋ค. (==๊ฐ ์คํจํ๋ค, ๋์ instance of ์ฌ์ฉํ๋ฉด ์ฑ๊ณต)
- ์์์ฑ ์ปจํ ์คํธ์ ์ฐพ๋ ์ํฐํฐ๊ฐ ์ด๋ฏธ ์์ผ๋ฉด em.getReference()๋ฅผ ํธ์ถํด๋ ์ค์ ์ํฐํฐ ๋ฐํ
- ์์์ฑ ์ปจํ ์คํธ์ ๋์์ ๋ฐ์ ์ ์๋ ์ค์์ ์ํ์ผ ๋, ํ๋ก์๋ฅผ ์ด๊ธฐํํ๋ฉด ๋ฌธ์ ๋ฐ์ (ํ์ด๋ฒ๋ค์ดํธ๋ org.hibernate.LazyInitializationException ์์ธ๋ฅผ ํฐํธ๋ฆผ)
ํ๋ก์ ๊ฐ์ฒด์ ์ด๊ธฐํ
Member member = em.getReference(Member.class, "id1");
member.getName();
getName์ ํ๋ฉด, ํ๋ก์ ๊ฐ์ฒด๊ฐ ์์์ฑ ์ปจํ ์คํธ์ ์ด๊ธฐํ๋ฅผ ์์ฒญํ๊ณ , DB๋ฅผ ์กฐํํด์ ์์์ฑ ์ปจํ ์คํธ์ ์ค์ ์ํฐํฐ๋ฅผ ์์ฑํ๊ณ target์ ์ฐ๊ฒฐํ๋ค.
ํ๋ก์ ํ์ธ
- ํ๋ก์ ์ธ์คํด์ค์ ์ด๊ธฐํ ์ฌ๋ถ ํ์ธ : emf.getPersistenceUnitUtil.isLoaded(PROXY)
- ํ๋ก์ ํด๋์ค ํ์ธ ๋ฐฉ๋ฒ : entity.getClass() ์ถ๋ ฅ(..javasist.. or HibernateProxy…)
- ํ๋ก์ ๊ฐ์ ์ด๊ธฐํ : org.hibernate.Hibernate.initialize(PROXY);
- ์ฐธ๊ณ : JPA ํ์ค์ ๊ฐ์ ์ด๊ธฐํ ์์. ๊ฐ์ ํธ์ถ: member.getName()
์ฆ์ ๋ก๋ฉ๊ณผ ์ง์ฐ ๋ก๋ฉ
์ง์ฐ ๋ก๋ฉ
@Entity
public class Member extends BaseEntity{
...
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TEAM_ID")
private Team team;
...
}
Team team = new Team();
team.setName("1๋ฐ2์ผ");
em.persist(team);
Member member = new Member();
member.setUsername("๊ฐํธ๋");
member.setTeam(team);
em.persist(member);
em.flush();
em.clear();
Member findMember = em.find(Member.class, member.getId());
System.out.println("=====================");
System.out.println(findMember.getTeam().getClass());
System.out.println("=====================");
System.out.println(findMember.getTeam().getName());
System.out.println(emf.getPersistenceUnitUtil().isLoaded(findMember.getTeam()));
System.out.println(findMember.getTeam().getClass());
System.out.println("=====================");
tx.commit();
์ง์ฐ ๋ก๋ฉ์ผ๋ก ์ค์ ํ ํ๋์ ํด๋์ค๋ฅผ ์กฐํํ๋ฉด, Proxy๋ผ๋ ๊ฒ์ ์ ์ ์๋ค.
์ค์ team์ ์ฌ์ฉํ๋ ์์ ์ ์ฟผ๋ฆฌ๋ฌธ์ด ๋ ๋ผ๊ฐ๋ค.
์ค์ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํด๋ Proxy ํ์ ์ด ์ฌ์ ํ ์ ์ง๋๋ค๋ ๊ฒ์ ์ ์ํ์.
์ฆ์ ๋ก๋ฉ
Team team = new Team();
team.setName("1๋ฐ2์ผ");
em.persist(team);
Member member = new Member();
member.setUsername("๊ฐํธ๋");
member.setTeam(team);
em.persist(member);
em.flush();
em.clear();
Member findMember = em.find(Member.class, member.getId());
System.out.println("=====================");
System.out.println(findMember.getTeam().getClass());
System.out.println(findMember.getTeam().getName());
System.out.println("=====================");
tx.commit();
์ค์ team์ ์ฌ์ฉํ๊ธฐ ์ ์ ์ด๋ฏธ ์ค์ ๊ฐ์ฒด๋ก ์ด๊ธฐํ๋์ด ์๋ค.
ํ๋ก์์ ์ฆ์ ๋ก๋ฉ ์ฃผ์
- ๊ฐ๊ธ์ ์ง์ฐ ๋ก๋ฉ๋ง ์ฌ์ฉ(ํนํ ์ค๋ฌด์์), ์ฆ์ ๋ก๋ฉ์ ํ๊ฒ ๋๋ฉด JOIN์ ๋ฌด์ํ ๋ง์ด ํ๊ธฐ ๋๋ฌธ์ ์ฑ๋ฅ์ด ์์ข์์ง.
- ์ฆ์ ๋ก๋ฉ์ ์ ์ฉํ๋ฉด ์์ํ์ง ๋ชปํ SQL์ด ๋ฐ์
- ์ฆ์ ๋ก๋ฉ์ JPQL์์ N+1 ๋ฌธ์ ๋ฅผ ์ผ์ผํจ๋ค.
List<Member> members = em.createQuery("select m from Member m", Member.class).getResultList();
SQL๋ฌธ select * from Member์ด ์คํ๋๊ณ , ์ฆ์ ๋ก๋ฉ์ ์ํด ๊ฐ member์ team๋ค์ด ์ฑ์์ ธ์ผ ํ๊ธฐ ๋๋ฌธ์ ์ถ๊ฐ์ ์ผ๋ก SQL๋ฌธ์ด ์คํ๋๋ค. ์ ์ฟผ๋ฆฌ ํ๋๋ก ์ป์ member๋ค ๊ฐ๊ฐ์ team์ ๋ก๋ฉํ๊ธฐ ์ํ N๊ฐ์ ์ฟผ๋ฆฌ๋ฌธ์ด ํ์ํ๋ค๋ ์๋ฏธ์ด๋ค.
- @ManyToOne, @OneToOne์ ๊ธฐ๋ณธ์ด ์ฆ์ ๋ก๋ฉ -> LAZY๋ก ์ค์
- @OneToMany, @ManyToMany๋ ๊ธฐ๋ณธ์ด ์ง์ฐ ๋ก๋ฉ
์ฐธ๊ณ ) JOIN : ๋ ๊ฐ์ ํ ์ด๋ธ์ ์ฎ์ด์ ์ํ๋ ๋ฐ์ดํฐ๋ฅผ ์ถ์ถํ ๋ ์ฌ์ฉํ๋ค.
์์์ฑ ์ ์ด : CASCADE
- ํน์ ์ํฐํฐ๋ฅผ ์์ ์ํ๋ก ๋ง๋ค ๋ ์ฐ๊ด๋ ์ํฐํฐ๋ ํจ๊ป ์์ ์ํ๋ก ๋ง๋ค๊ณ ์ถ์ ๋ ์ฌ์ฉํ๋ค. ์๋ฅผ ๋ค์ด ๋ถ๋ชจ ์ํฐํฐ๋ฅผ ์ ์ฅํ ๋ ์์ ์ํฐํฐ๋ ํจ๊ป ์ ์ฅํ๊ณ ์ถ์ ๋ ์ฌ์ฉํ๋ค.
- ์์์ฑ ์ ์ด๋ ์ฐ๊ด๊ด๊ณ๋ฅผ ๋งคํํ๋ ๊ฒ๊ณผ๋ ์๋ฌด ๊ด๋ จ์ด ์๋ค. ์ํฐํฐ๋ฅผ ์์ํํ ๋ ์ฐ๊ด๋ ์ํฐํฐ๋ ํจ๊ป ์์ํํ๋ ํธ๋ฆฌํจ์ ์ ๊ณตํ ๋ฟ์ด๋ค.
- ์ต์ ์์ ALL๊ณผ PERSIST๋ฅผ ์ฃผ๋ก ์ฌ์ฉํ๋ค.
- ์์ ์๊ฐ ํ๋์ผ ๋, ์๋ฅผ ๋ค์ด Child๊ฐ Parent์๋ง ๊ด๋ จ์ด ์์ ๋๋ง ์ฌ์ฉํ๋ค.
Child child1 = new Child();
Child child2 = new Child();
Parent parent = new Parent();
parent.addChild(child1);
parent.addChild(child2);
// em.persist(child1);
// em.persist(child2);
em.persist(parent);
List<Child> childList = em.find(Parent.class, parent.getId()).getChildList();
for (Child child : childList) {
System.out.println("child = " + child);
}
tx.commit();
์ ์ฝ๋์์ parent ๊ฐ์ฒด์๋ child ๊ฐ์ฒด๋ค์ด ์ ์ฅ๋์ด ์์ง๋ง, em.find๋ก ๊ฐ์ ธ์จ ๊ฐ์ฒด์๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์๋ child๊ฐ ์์ผ๋ฏ๋ก ๋ฐ์๋์ง ์๋๋ค.
@Entity
public class Parent {
...
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
private List<Child> childList = new ArrayList<>();
// ์ฐ๊ด๊ด๊ณ ๋ฉ์๋
public void addChild(Child child){
child.setParent(this);
childList.add(child);
}
...
}
cascade๋ฅผ ์ค์ ํ๋ฉด, parent๋ง persistํด๋ ์ปฌ๋ ์ ์ ์๋ child๋ค๊น์ง persist ๋๋ค.
๊ณ ์ ๊ฐ์ฒด
- ๋ถ๋ชจ ์ํฐํฐ์ ์ฐ๊ด๊ด๊ณ๊ฐ ๋์ด์ง ์์ ์ํฐํฐ๋ฅผ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์๋ ์ญ์ ์ํจ๋ค.
- ์ฐธ์กฐํ๋ ๊ณณ์ด ํ๋์ผ ๋ ์ฌ์ฉํด์ผ ํจ, ์ฆ ํน์ ์ํฐํฐ๊ฐ ๊ฐ์ธ ์์ ํ ๋ ์ฌ์ฉ
- @OneToOne, @OneToMany๋ง ๊ฐ๋ฅ
@Entity
public class Parent {
...
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Child> childList = new ArrayList<>();
...
}
Parent findParent = em.find(Parent.class, parent.getId());
findParent.getChildList().remove(0);
- em.remove๋ก ๋ถ๋ชจ๋ฅผ ์ญ์ ํ๋ฉด, ์์๋ ์ญ์ ๋๋ค.
์์์ฑ ์ ์ด + ๊ณ ์ ๊ฐ์ฒด
- CascadeType.ALL + orphanRemoval=true
- ์ค์ค๋ก ์๋ช ์ฃผ๊ธฐ๋ฅผ ๊ด๋ฆฌํ๋ ์ํฐํฐ๋ em.persist()๋ก ์์ํ, em.remove()๋ก ์ ๊ฑฐ
- ๋ ์ต์ ์ ๋ชจ๋ ํ์ฑํ ํ๋ฉด ๋ถ๋ชจ ์ํฐํฐ๋ฅผ ํตํด์ ์์์ ์๋ช ์ฃผ๊ธฐ๋ฅผ ๊ด๋ฆฌํ ์ ์์
- ๋๋ฉ์ธ ์ฃผ๋ ์ค๊ณ(DDD)์ Aggregate Root๊ฐ๋ ์ ๊ตฌํํ ๋ ์ ์ฉ
๊ฐ ํ์
JPA์ ๋ฐ์ดํฐ ํ์ ๋ถ๋ฅ
- ์ํฐํฐ ํ์
- @Entity๋ก ์ ์ํ๋ ๊ฐ์ฒด
- ๋ฐ์ดํฐ๊ฐ ๋ณํด๋ ์๋ณ์(id)๋ก ์ง์ํด์ ์ถ์ ๊ฐ๋ฅ
- ๊ฐ ํ์
- int, String์ฒ๋ผ ๋จ์ํ ๊ฐ์ผ๋ก ์ฌ์ฉํ๋ ์๋ฐ ๊ธฐ๋ณธ ํ์ ์ด๋ ๊ฐ์ฒด
- ์๋ณ์๊ฐ ์๊ณ ๊ฐ๋ง ์์ผ๋ฏ๋ก ๋ณ๊ฒฝ ์ ์ถ์ ๋ถ๊ฐ, ์๋ฅผ ๋ค์ด ์ด๋ฆ์ ๋ณ๊ฒฝํ๋ฉด ์์ ํ ๋ค๋ฅธ ๊ฐ์ผ๋ก ๋์ฒด
๊ฐ ํ์ ๋ถ๋ฅ
- ๊ธฐ๋ณธ๊ฐ ํ์
- ์๋ฐ ๊ธฐ๋ณธ ํ์ (int, double)
- ๋ํผ ํด๋์ค(Integer, Long)
- String
- ์๋ฒ ๋๋ ํ์ (embedded type, ๋ณตํฉ๊ฐ ํ์ ) : ์ขํ, ์ฃผ์ ๊ฐ์ด ๋ฌถ์ด์ ์ฐ๊ณ ์ถ์ ๋
- ์ปฌ๋ ์ ๊ฐ ํ์ : ์๋ฐ ์ปฌ๋ ์
๊ธฐ๋ณธ๊ฐ ํ์
- ์๋ช ์ฃผ๊ธฐ๋ฅผ ์ํฐํฐ์ ์์กด, ์๋ฅผ ๋ค์ด ํ์์ ์ญ์ ํ๋ฉด ์ด๋ฆ, ๋์ด ํ๋๋ ํจ๊ป ์ญ์
- ๊ฐ ํ์ ์ ๊ณต์ ํ๋ฉด ์๋จ, ์๋ฅผ ๋ค์ด ํ์ ์ด๋ฆ ๋ณ๊ฒฝ ์ ๋ค๋ฅธ ํ์์ ์ด๋ฆ๋ ํจ๊ป ๋ณ๊ฒฝํ๋ฉด ์๋จ
- ์๋ฐ ๊ธฐ๋ณธ ํ์ ์ ๊ณต์ ๋์ง ์๊ณ , ๊ฐ์ ๋ณต์ฌํจ, ํ์ง๋ง, ๋ํผ ํด๋์ค๋ String ๊ฐ์ ํน์ํ ํด๋์ค๋ ๊ณต์ ๊ฐ๋ฅํ ๊ฐ์ฒด์ด์ง๋ง ๋ณ๊ฒฝ ๋ถ๊ฐ
์๋ฒ ๋๋ ํ์
- ์๋ก์ด ๊ฐ ํ์ ์ ์ง์ ์ ์ํ ์ ์์
- ์ฃผ๋ก ๊ธฐ๋ณธ ๊ฐ ํ์ ์ ๋ชจ์์ ๋ง๋ค์ด์ ๋ณตํฉ ๊ฐ ํ์ ์ด๋ผ๊ณ ๋ ํจ
- int, String๊ณผ ๊ฐ์ ๊ฐ ํ์ , ๊ฐ์ผ๋ก ์ฌ์ฉํจ
- @Embeddable๋ก ์ ์ํ๊ณ , @Embedded๋ก ์ฌ์ฉ
์๋ฒ ๋๋ ํ์ ์ ์ฅ์
- ์ฌ์ฌ์ฉ
- ๋์ ์์ง๋
- Period.isWork()์ฒ๋ผ ํด๋น ๊ฐ ํ์ ๋ง ์ฌ์ฉํ๋ ์๋ฏธ ์๋ ๋ฉ์๋๋ฅผ ๋ง๋ค ์ ์์.
- ์๋ฒ ๋๋ ํ์ ์ ํฌํจํ ๋ชจ๋ ๊ฐ ํ์ ์, ๊ฐ ํ์ ์ ์์ ํ ์ํฐํฐ์ ์๋ช ์ฃผ๊ธฐ๋ฅผ ์์กดํจ.
์๋ฒ ๋๋ ํ์ ๊ณผ ํ ์ด๋ธ ๋งคํ
์๋ฒ ๋๋ ํ์ ๊ณผ ํ ์ด๋ธ ๋งคํ
- ์๋ฒ ๋๋ ํ์ ์ ์ํฐํฐ์ ๊ฐ์ผ ๋ฟ์ด๋ค.
- ์๋ฒ ๋๋ ํ์ ์ ์ฌ์ฉํ๊ธฐ ์ ๊ณผ ํ์ ๋งคํํ๋ ํ ์ด๋ธ์ ๊ฐ๋ค.
- ๊ฐ์ฒด์ ํ ์ด๋ธ์ ์์ฃผ ์ธ๋ฐํ๊ฒ ๋งคํํ๋ ๊ฒ์ด ๊ฐ๋ฅํ๋ค.
- ์ ์ค๊ณํ ORM ์ ํ๋ฆฌ์ผ์ด์ ์ ๋งคํํ ํ ์ด๋ธ์ ์๋ณด๋ค ํด๋์ค์ ์๊ฐ ๋ ๋ง๋ค.
- ์๋ฒ ๋๋ ํ์ ํ๋๋ฅผ null๋ก ์ ์ํ๋ฉด, ๊ทธ ์์ ์๋ ํ๋๋ค๋ null๋ก ๋์ด ํ ์ด๋ธ์ ๋ฐ์๋๋ค.
์๋ฒ ๋๋ ํ์ ๊ณผ ์ฐ๊ด๊ด๊ณ
@AttributeOverride: ์์ฑ ์ฌ์ ์
- ํ ์ํฐํฐ์์ ์๋ฒ ๋๋ ํ์ ์ ๋ ๋ฒ ์ด์ ์ฌ์ฉํ๋ฉด ์ค๋ณต๋๊ธฐ ๋๋ฌธ์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค.
- @AttributeOverrides, @AttributeOverride๋ฅผ ์ฌ์ฉํด์ ์ปฌ๋ผ ๋ช ์์ฑ์ ์ฌ์ ์ํ๋ฏ๋ก์จ ํด๊ฒฐํ ์ ์๋ค.
@Embedded
private Address homeAddress;
@Embedded
@AttributeOverrides({
@AttributeOverride(name="city",
column=@Column(name = "SCHOOL_CITY")),
@AttributeOverride(name="street",
column=@Column(name = "SCHOOL_STREET")),
@AttributeOverride(name="zipcode",
column=@Column(name = "SCHOOL_ZIPCODE"))})
private Address schoolAddress;
๊ฐ ํ์ ๊ณผ ๋ถ๋ณ ๊ฐ์ฒด
๊ฐ ํ์ ๊ณต์ ์ฐธ์กฐ
- ์๋ฒ ๋๋ ํ์ ๊ฐ์ ๊ฐ ํ์ ์ ์ฌ๋ฌ ์ํฐํฐ์์ ๊ณต์ ํ๋ฉด ์ํํ๋ค.
Address address = new Address("๋ง์ฐ", "๊ฑฐ๋ฆฌ1", "1000");
Member member1 = new Member();
member1.setUsername("๊ฐํธ๋");
member1.setHomeAddress(address);
em.persist(member1);
Member member2 = new Member();
member2.setUsername("์ด์๊ทผ");
member2.setHomeAddress(address);
em.persist(member2);
member1.getHomeAddress().setCity("์์ธ");
- ๊ฐ ํ์ ์ ์ค์ ์ธ์คํด์ค๋ฅผ ๊ณต์ ํ๋ ๊ฒ์ ์ํํ๋ค.
- ์๋ก์ด ์ธ์คํด์ค๋ฅผ ๋ง๋ค๊ณ , ๊ฐ์ ๋ณต์ฌํด์ ์ฌ์ฉํด์ผ ํ๋ค.
๊ฐ์ฒด ํ์ ์ ํ๊ณ
- ๊ณต์ ์ฐธ์กฐ๋ก ์ธํด ๋ฐ์ํ๋ ๋ถ์์ฉ์ ํผํ๊ธฐ ์ํด ํญ์ ๊ฐ์ ๋ณต์ฌํด์ ์ฌ์ฉํด์ผ ํ๋ค.
- ๋ฌธ์ ๋ ์๋ฒ ๋๋ ํ์ ์ฒ๋ผ ์ง์ ์ ์ํ ๊ฐ ํ์ ์ ์๋ฐ์ ๊ธฐ๋ณธ ํ์ ์ด ์๋๋ผ ๊ฐ์ฒด ํ์ ์ด๋ค.
- ๊ฐ์ฒด ํ์ ์ ์ฐธ์กฐ ๊ฐ์ ์ง์ ๋์ ํ๋ ๊ฒ์ ๋ง์ ๋ฐฉ๋ฒ์ด ์๋ค. ๊ฐ์ฒด์ ๊ณต์ ์ฐธ์กฐ๋ ํผํ ์ ์๋ค.
๋ถ๋ณ ๊ฐ์ฒด
- ๊ฐ์ฒด ํ์ ์ ์์ ํ ์ ์๊ฒ ๋ง๋ค๋ฉด ๋ถ์์ฉ์ ์์ฒ ์ฐจ๋จํ ์ ์๋ค.
- ๊ฐ ํ์ ์ ๋ถ๋ณ ๊ฐ์ฒด(immutable object)๋ก ์ค๊ณํด์ผ ํ๋ค. ๋ถ๋ณ ๊ฐ์ฒด๋ ์์ฑ ์์ ์ดํ ์ ๋ ๊ฐ์ ๋ณ๊ฒฝํ ์ ์๋ ๊ฐ์ฒด
- ์์ฑ์๋ก ์์ฑ ์์ ์๋ง ๊ฐ์ ์ค์ ํ๊ณ , Setter๋ฅผ ๋ง๋ค์ง ์๊ฑฐ๋ private์ผ๋ก ์์ฑํด์ผ ํ๋ค. ์ด๋ ๊ฒ ํ๋ฉด, ๊ฐ์ ๋ฐ๊พธ๊ณ ์ถ์ด๋ ๋ฐ๊พธ์ง ๋ชปํ๋ฏ๋ก ์๋ก ์ธ์คํด์ค๋ฅผ ๋ง๋ค๊ณ , ๊ฐ์ ๋ณต์ฌํ์ฌ ์ํ๋ ๋ถ๋ถ๋ง ๋ฐ๊พธ๊ณ ๋ฃ์ด์ฃผ์ด์ผ ํ๋ค.
Address address = new Address("๋ง์ฐ", "๊ฑฐ๋ฆฌ1", "1000");
Member member1 = new Member();
member1.setUsername("๊ฐํธ๋");
member1.setHomeAddress(address);
em.persist(member1);
Address newAddress = new Address("์์ธ", member1.getHomeAddress().getStreet(), member1.getHomeAddress().getZipcode());
member1.setHomeAddress(newAddress);
- ์ฐธ๊ณ ) Integer, String์ ์๋ฐ๊ฐ ์ ๊ณตํ๋ ๋ํ์ ์ธ ๋ถ๋ณ ๊ฐ์ฒด
๊ฐ ํ์ ์ ๋น๊ต
- ๋์ผ์ฑ(identity) ๋น๊ต: ์ธ์คํด์ค์ ์ฐธ์กฐ ๊ฐ์ ๋น๊ต, == ์ฌ์ฉ
- ๋๋ฑ์ฑ(equivalence) ๋น๊ต: ์ธ์คํด์ค์ ๊ฐ์ ๋น๊ต, ํด๋์ค์์ equals()๋ฅผ overrideํด์ ์ฌ์ฉํด์ผ ํ๋ค.
- ๊ฐ ํ์ ์ a.equals(b)๋ฅผ ์ฌ์ฉํด์ ๋๋ฑ์ฑ ๋น๊ต๋ฅผ ํด์ผ ํจ
๊ฐ ํ์ ์ปฌ๋ ์
- ์ฐ์ง ์๋ ๊ฒ์ด ์ข๋ค.
- ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค์๋ ์ปฌ๋ ์ ์ ์ ์ฅํ ์ ์๋ค. ๋ฐ๋ผ์ ์ปฌ๋ ์ ์ ๋ฐ๋ก ํ ์ด๋ธ๋ก ๋ง๋ค์ด์ผ ํ๋ค.
- ๊ฐ ํ์ ์ ํ๋ ์ด์ ์ ์ฅํ ๋ ์ฌ์ฉํ๋ค.
- @ElementCollection, @CollectionTable ์ฌ์ฉํ๋ค.
- ๊ธฐ๋ณธ์ ์ผ๋ก ์ง์ฐ ๋ก๋ฉ ์ ๋ต์ ์ฌ์ฉํ๋ค.
@ElementCollection
@CollectionTable(name = "FAVORITE_FOOD",
joinColumns = @JoinColumn(name = "MEMBER_ID"))
@Column(name = "FOOD_NAME")
private Set<String> favoriteFoods = new HashSet<>();
@ElementCollection
@CollectionTable(name = "ADDRESS",
joinColumns = @JoinColumn(name = "MEMBER_ID"))
private List<Address> addressHistory = new ArrayList<>();
๊ฐ ํ์ ์ปฌ๋ ์ ๋ ๊ฐ ํ์ ์ด๋ฏ๋ก ์ํฐํฐ์ ์๋ช ์ฃผ๊ธฐ์ ์ผ์นํ๋ค. ๊ฐ ํ์ ์ปฌ๋ ์ ์ ์์์ฑ ์ ์(Cascade) + ๊ณ ์ ๊ฐ์ฒด ์ ๊ฑฐ ๊ธฐ๋ฅ์ ํ์๋ก ๊ฐ์ง๋ค๊ณ ๋ณผ ์ ์๋ค.
๊ฐ ํ์ ์ปฌ๋ ์ ์์
findMember.getFavoriteFoods().remove("์นํจ");
findMember.getFavoriteFoods().add("์กฑ๋ฐ");
findMember.getAddressHistory().remove(new Address("old1", "street1", "zipcode1"));
findMember.getAddressHistory().add(new Address("new1", "street1", "zipcode1"));
๊ฐ ํ์ ์ปฌ๋ ์ ์ ์ ์ฝ์ฌํญ
- ๊ฐ ํ์ ์ ์ํฐํฐ์ ๋ค๋ฅด๊ฒ ์๋ณ์ ๊ฐ๋ ์ด ์๋ค.
- ๊ฐ์ ๋ณ๊ฒฝํ๋ฉด ์ถ์ ์ด ์ด๋ ต๋ค.
- ๊ฐ ํ์ ์ปฌ๋ ์ ์ ๋ณ๊ฒฝ ์ฌํญ์ด ๋ฐ์ํ๋ฉด, ์ฃผ์ธ ์ํฐํฐ์ ์ฐ๊ด๋ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ์ญ์ ํ๊ณ , ๊ฐ ํ์ ์ปฌ๋ ์ ์ ์๋ ํ์ฌ ๊ฐ์ ๋ชจ๋ ๋ค์ ์ ์ฅํ๋ค. -> ๊ฒฐ๋ก ์ ์ผ๋ก ์ฐ๋ฉด ์๋๋ค.
- ๊ฐ ํ์ ์ปฌ๋ ์ ์ ๋งคํํ๋ ํ ์ด๋ธ์ ๋ชจ๋ ์ปฌ๋ผ์ ๋ฌถ์ด์ ๊ธฐ๋ณธ ํค๋ฅผ ๊ตฌ์ฑํด์ผ ํ๋ค: null ์ ๋ ฅX, ์ค๋ณต ์ ์ฅX
๊ฐ ํ์ ์ปฌ๋ ์ ๋์
- ์ค๋ฌด์์๋ ์ํฉ์ ๋ฐ๋ผ ๊ฐ ํ์ ์ปฌ๋ ์ ๋์ ์ ์ผ๋๋ค ๊ด๊ณ๋ฅผ ๊ณ ๋ ค
- ์ผ๋๋ค ๊ด๊ณ๋ฅผ ์ํ ์ํฐํฐ๋ฅผ ๋ง๋ค๊ณ , ์ฌ๊ธฐ์์ ๊ฐ ํ์ ์ ์ฌ์ฉ
- ์์์ฑ ์ ์ด(Cascade) + ๊ณ ์ ๊ฐ์ฒด ์ ๊ฑฐ๋ฅผ ์ฌ์ฉํด์ ๊ฐ ํ์ ์ปฌ๋ ์ ์ฒ๋ผ ์ฌ์ฉ
- EX) AddressEntity
package hellojpa;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
@Entity
@Table(name = "ADDRESS")
public class AddressEntity {
@Id
@GeneratedValue
private Long id;
private Address address;
public AddressEntity() {
}
public AddressEntity(String city, String street, String zipcode) {
this.address = new Address(city, street, zipcode);
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
JPQL
JPA์ ์ฟผ๋ฆฌ ๋ฐฉ๋ฒ
- JPQL
- JPA๊ฐ ์ ๊ณตํ๋ SQL์ ์ถ์ํํ ๊ฐ์ฒด ์งํฅ ์ฟผ๋ฆฌ ์ธ์ด, SQL๊ณผ ๋ฌธ๋ฒ ์ ์ฌํ๋ค.
- JPQL์ ์ํฐํฐ ๊ฐ์ฒด๋ฅผ ๋์์ผ๋ก ์ฟผ๋ฆฌ, SQL์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ ์ด๋ธ์ ๋์์ผ๋ก ์ฟผ๋ฆฌํ๋ค.
- JPQL์ ๊ฒฐ๊ตญ SQL๋ก ๋ณํ๋๋ค.
List<Member> members = em.createQuery("select m from Member m where m.username like '%kim%'", Member.class).getResultList();
- QueryDSL
- SpringJdbcTemplate
- JPA๋ฅผ ์ฐํํด์ SQL์ ์คํํ ๋๋ ์์์ฑ ์ปจํ ์คํธ๊ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฐ์๋์ง ์๊ธฐ ๋๋ฌธ์ ๊ทธ ์ ์ ์์์ฑ ์ปจํ ์คํธ๋ฅผ ์ ์ ํ ์์ ์ ๊ฐ์ ๋ก ํ๋ฌ์ํ๋ ๊ฒ์ด ํ์ํ๋ค.
JPQL
Java Persistence Query Language
JPQL ๋ฌธ๋ฒ
- select m from Member as m where m.age > 18
- ์ํฐํฐ(Member)์ ์์ฑ(age)์ ๋์๋ฌธ์๋ฅผ ๊ตฌ๋ถํ๋ค.
- JPQL(SELECT, FROM, where) ํค์๋๋ ๋์๋ฌธ์๋ฅผ ๊ตฌ๋ถํ์ง ์๋๋ค.
- ํ ์ด๋ธ ์ด๋ฆ์ด ์๋๋ผ ์ํฐํฐ ์ด๋ฆ(Member)์ ์ฌ์ฉํ๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก ํด๋์ค ์ด๋ฆ์ด๋ค.
- ๋ณ์นญ(m)์ ํ์ (as๋ ์๋ต๊ฐ๋ฅ)
์งํฉ๊ณผ ์ ๋ ฌ
select
COUNT(m), //ํ์์
SUM(m.age), //๋์ด ํฉ
AVG(m.age), //ํ๊ท ๋์ด
MAX(m.age), //์ต๋ ๋์ด
MIN(m.age) //์ต์ ๋์ด
from Member m
GROUP BY, HAVING, ORDER BY
TypeQuery, Query
- TypeQuery: ๋ฐํ ํ์ ์ด ๋ช ํํ ๋ ์ฌ์ฉ
TypedQuery<Member> query = em.createQuery("SELECT m FROM Member m", Member.class);
- Query: ๋ฐํ ํ์ ์ด ๋ช ํํ์ง ์์ ๋ ์ฌ์ฉ
Query query = em.createQuery("SELECT m.username, m.age from Member m");
๊ฒฐ๊ณผ ์กฐํ API
- query.getResultList(): ๊ฒฐ๊ณผ๊ฐ ํ๋ ์ด์์ผ ๋, ๋ฆฌ์คํธ ๋ฐํ, ๊ฒฐ๊ณผ๊ฐ ์์ผ๋ฉด ๋น ๋ฆฌ์คํธ ๋ฐํ
- query.getSingleResult(): ๊ฒฐ๊ณผ๊ฐ ์ ํํ ํ๋, ๋จ์ผ ๊ฐ์ฒด ๋ฐํ
- ๊ฒฐ๊ณผ๊ฐ ์์ผ๋ฉด: jakarta.persistence.NoResultException
- ๋ ์ด์์ด๋ฉด: jakarta.persistence.NonUniqueResultException
ํ๋ก์ ์ (SELECT)
- SELECT ์ ์ ์กฐํํ ๋์์ ์ง์ ํ๋ ๊ฒ
- ํ๋ก์ ์ ๋์: ์ํฐํฐ, ์๋ฒ ๋๋ ํ์ , ์ค์นผ๋ผ ํ์ (์ซ์, ๋ฌธ์๋ฑ ๊ธฐ๋ณธ ๋ฐ์ดํฐ ํ์ )
- SELECT m FROM Member m -> m์ด Member์ด๋ฏ๋ก ์ํฐํฐ ํ๋ก์ ์
- SELECT m.team FROM Member m -> m๊ณผ ์ฐ๊ด๋ team์ด ์ํฐํฐ์ด๋ฏ๋ก, ์ํฐํฐ ํ๋ก์ ์
- SELECT m.address FROM Member m -> ์๋ฒ ๋๋ ํ์ ํ๋ก์ ์
- SELECT m.username, m.age FROM Member m -> ์ค์นผ๋ผ ํ์ ํ๋ก์ ์
- DISTINCT๋ก ์ค๋ณต ์ ๊ฑฐํ ์ ์๋ค.
- ์กฐํํ ๊ฒฐ๊ณผ๋ ์์์ฑ ์ปจํ ์คํธ๋ก ๊ด๋ฆฌ๋๋ค.
ํ๋ก์ ์ - ์ฌ๋ฌ ๊ฐ ์กฐํ
SELECT m.username, m.age FROM Member m
- 1. Query ํ์ ์ผ๋ก ์กฐํ
- 2. Object[] ํ์ ์ผ๋ก ์กฐํ
- 3. new ๋ช
๋ น์ด๋ก ์กฐํ
- ๋จ์ ๊ฐ์ DTO๋ก ๋ฐ๋ก ์กฐํ
- ํจํค์ง ๋ช ์ ํฌํจํ ์ ์ฒด ํด๋์ค ๋ช ์ ๋ ฅ
- ์์์ ํ์ ์ด ์ผ์นํ๋ ์์ฑ์ ํ์
List<MemberDto> resultList = em.createQuery("select new jpql.MemberDto(m.username, m.age) from Member m", MemberDto.class).getResultList();
ํ์ด์ง
- setFirstResult(int startPosition) : ์กฐํ ์์ ์์น (0๋ถํฐ ์์)
- setMaxResults(int maxResult) : ์กฐํํ ๋ฐ์ดํฐ ์
List<Member> resultList = em.createQuery("select m from Member m order by m.age desc", Member.class).setFirstResult(1).setMaxResults(10).getResultList();
์กฐ์ธ
id๊ฐ ๊ธฐ๋ณธ ์กฐ๊ฑด
- ๋ด๋ถ ์กฐ์ธ: ๋ ํ ์ด๋ธ์ ์กฐ์ธํ ๋, ๋ ํ ์ด๋ธ์ ๋ชจ๋ ์ง์ ํ ์ด์ ๋ฐ์ดํฐ๊ฐ ์์ด์ผ ํ๋ค. ์์ผ๋ฉด ๊ฒฐ๊ณผ์ ํฌํจ๋์ง ์๋๋ค.
SELECT m FROM Member m [INNER] JOIN m.team t
- ์ธ๋ถ ์กฐ์ธ: OUTER JOIN(์ธ๋ถ ์กฐ์ธ)์ ๋ ํ ์ด๋ธ์ ์กฐ์ธํ ๋, 1๊ฐ์ ํ ์ด๋ธ์๋ง ๋ฐ์ดํฐ๊ฐ ์์ด๋ ๊ฒฐ๊ณผ๊ฐ ๋์จ๋ค.
SELECT m FROM Member m LEFT [OUTER] JOIN m.team t
- ์ธํ ์กฐ์ธ: ๊ณฑ์งํฉ
select count(m) from Member m, Team t where m.username = t.name
์กฐ์ธ - ON ์
- ์กฐ์ธ ๋์ ํํฐ๋ง
์) ํ์๊ณผ ํ์ ์กฐ์ธํ๋ฉด์, ํ ์ด๋ฆ์ด A์ธ ํ๋ง ์กฐ์ธ
SELECT m, t FROM Member m LEFT JOIN m.team t on t.name = 'A' //JPQL
SELECT m.*, t.* FROM Member m LEFT JOIN Team t ON m.TEAM_ID=t.id and t.name='A' //SQL
- ์ฐ๊ด๊ด๊ณ ์๋ ์ํฐํฐ ์ธ๋ถ ์กฐ์ธ ๊ฐ๋ฅ
์) ํ์์ ์ด๋ฆ๊ณผ ํ์ ์ด๋ฆ์ด ๊ฐ์ ๋์ ์ธ๋ถ ์กฐ์ธ
SELECT m, t FROM Member m LEFT JOIN Team t on m.username = t.name //JPQL
SELECT m.*, t.* FROM Member m LEFT JOIN Team t ON m.username = t.name //SQL
์๋ธ ์ฟผ๋ฆฌ
- ๋์ด๊ฐ ํ๊ท ๋ณด๋ค ๋ง์ ํ์
select m from Member m where m.age > (select avg(m2.age) from Member m2)
- ํ ๊ฑด์ด๋ผ๋ ์ฃผ๋ฌธํ ๊ณ ๊ฐ
select m from Member m where (select count(o) from Order where o.member = m) > 0
์๋ธ ์ฟผ๋ฆฌ ์ง์ ํจ์
- [NOT] EXISTS (subquery): ์๋ธ์ฟผ๋ฆฌ์ ๊ฒฐ๊ณผ๊ฐ ์กด์ฌํ๋ฉด ์ฐธ
- {ALL | ANY | SOME} (subquery)
- ALL ๋ชจ๋ ๋ง์กฑํ๋ฉด ์ฐธ
- ANY, SOME: ๊ฐ์ ์๋ฏธ, ์กฐ๊ฑด์ ํ๋๋ผ๋ ๋ง์กฑํ๋ฉด ์ฐธ
- [NOT] IN (subquery): ์๋ธ์ฟผ๋ฆฌ์ ๊ฒฐ๊ณผ ์ค ํ๋๋ผ๋ ๊ฐ์ ๊ฒ์ด ์์ผ๋ฉด ์ฐธ
์์
- ํA ์์์ธ ํ์
select m from Member m where exists (select t from m.team t where t.name = 'ํA')
- ์ ์ฒด ์ํ ๊ฐ๊ฐ์ ์ฌ๊ณ ๋ณด๋ค ์ฃผ๋ฌธ๋์ด ๋ง์ ์ฃผ๋ฌธ๋ค
select o from Order o where o.orderAmount > ALL (select p.stockAmount from Product p)
- ์ด๋ค ํ์ด๋ ํ์ ์์๋ ํ์
select m from Member m where m.team = ANY (select t from Team t)
JPA ์๋ธ ์ฟผ๋ฆฌ ํ๊ณ
FROM ์ ์์ ์๋ธ ์ฟผ๋ฆฌ ๋ถ๊ฐ๋ฅ
JPQL ํ์ ํํ๊ณผ ๊ธฐํ์
- ๋ฌธ์: ‘HELLO’, ‘She’’s’
- ์ซ์: 10L(Long), 10D(Double), 10F(Float)
- Boolean: TRUE, FALSE
- ENUM: jpabook.MemberType.Admin (ํจํค์ง๋ช ํฌํจ)
- ์ํฐํฐ ํ์ : TYPE(m) = Member (์์ ๊ด๊ณ์์ ์ฌ์ฉ) ex) type(i) = Book
select m.username, 'Hello', TRUE from Member m where m.type jpql.MemberType.ADMIN
- EXISTS, IN
- AND, OR, NOT
- =, >, >=, <, <=, <>
- BETWEEN, LIKE, IS NULL
์กฐ๊ฑด์ - CASE ์
select
case when m.age <= 10 then 'ํ์์๊ธ'
when m.age >= 60 then '๊ฒฝ๋ก์๊ธ'
else '์ผ๋ฐ์๊ธ'
end
from Member m
select
case t.name
when 'ํA' then '์ธ์ผํฐ๋ธ110%'
when 'ํB' then '์ธ์ผํฐ๋ธ120%'
else '์ธ์ผํฐ๋ธ105%'
end
from Team t
- COALESCE : ํ๋์ฉ ์กฐํํด์ null์ด ์๋๋ฉด ์ฒซ ๋ฒ์งธ ๊ฐ ๋ฐํ, null์ด๋ฉด ๋ ๋ฒ์งธ ๊ฐ ๋ฐํ
select coalesce(m.username,'์ด๋ฆ ์๋ ํ์') from Member m
- NULLIF : ๋ ๊ฐ์ด ๊ฐ์ผ๋ฉด null ๋ฐํ, ๋ค๋ฅด๋ฉด ์ฒซ ๋ฒ์งธ ๊ฐ ๋ฐํ
select NULLIF(m.username, '๊ด๋ฆฌ์') from Member m
JPQL ๊ธฐ๋ณธ ํจ์
๋ฐ์ดํฐ๋ฒ ์ด์ค ์๊ด์์ด ์ฌ์ฉ ๊ฐ๋ฅํ๋ค.
- CONCAT
- SUBSTRING
- TRIM
- LOWER, UPPER
- LENGTH
- LOCATE
- ABS, SQRT, MOD
- SIZE, INDEX(JPA ์ฉ๋)
๊ฒฝ๋ก ํํ์
์ ์ ์ฐ์ด ๊ฐ์ฒด ๊ทธ๋ํ๋ฅผ ํ์ํ๋ ๊ฒ
select m.username -> ์ํ ํ๋ (๊ทธ๋ฅ ๊ฐ)
from Member m
join m.team t -> ๋จ์ผ ๊ฐ ์ฐ๊ด ํ๋ (์ํฐํฐ)
join m.orders o -> ์ปฌ๋ ์
๊ฐ ์ฐ๊ด ํ๋ (์ํฐํฐ ์ปฌ๋ ์
)
where t.name = 'ํA'
- ์ํ ํ๋(state field): ๋จ์ํ ๊ฐ์ ์ ์ฅํ๊ธฐ ์ํ ํ๋ (ex: m.username)
- ์ฐ๊ด ํ๋(association field): ์ฐ๊ด๊ด๊ณ๋ฅผ ์ํ ํ๋
- ๋จ์ผ ๊ฐ ์ฐ๊ด ํ๋: @ManyToOne, @OneToOne, ๋์์ด ์ํฐํฐ(ex: m.team)
- ์ปฌ๋ ์ ๊ฐ ์ฐ๊ด ํ๋: @OneToMany, @ManyToMany, ๋์์ด ์ปฌ๋ ์ (ex: m.orders)
๊ฒฝ๋ก ํํ์ ํน์ง
- ์ํ ํ๋(state field): ๊ฒฝ๋ก ํ์์ ๋, m.username์์ ์ถ๊ฐ๋ก .์ ์ฐ์ ์ ์์
select m.username from Member m
- ๋จ์ผ ๊ฐ ์ฐ๊ด ๊ฒฝ๋ก: ๋ฌต์์ ๋ด๋ถ ์กฐ์ธ(inner join) ๋ฐ์, ํ์O
select o.member from Order o
- ์ปฌ๋ ์
๊ฐ ์ฐ๊ด ๊ฒฝ๋ก: ๋ฌต์์ ๋ด๋ถ ์กฐ์ธ ๋ฐ์, ํ์X, t.members์ ๋ง์ member๋ค์ด ์๊ธฐ ๋๋ฌธ์ ์ถ๊ฐ๋ก .์ ์ฐ์ ์ ์์
- FROM ์ ์์ ๋ช ์์ ์กฐ์ธ์ ํตํด ๋ณ์นญ์ ์ป์ผ๋ฉด ๋ณ์นญ์ ํตํด ํ์ ๊ฐ๋ฅ
select t.members from Team t
select m.username from Team t join t.members m
๋ช ์์ ์กฐ์ธ, ๋ฌต์์ ์กฐ์ธ
- ๋ช ์์ ์กฐ์ธ: join ํค์๋๋ฅผ ์ง์ ์ฌ์ฉ, select m from Member m join m.team t
- ๋ฌต์์ ์กฐ์ธ: ๊ฒฝ๋ก ํํ์์ ์ํด ๋ฌต์์ ์ผ๋ก SQL ์กฐ์ธ ๋ฐ์(๋ด๋ถ ์กฐ์ธ๋ง ๊ฐ๋ฅ), select m.team from Member m
์ค๋ฌด ์กฐ์ธ
- ๊ฐ๊ธ์ ๋ฌต์์ ์กฐ์ธ ๋์ ์ ๋ช ์์ ์กฐ์ธ ์ฌ์ฉ
- ์กฐ์ธ์ SQL ํ๋์ ์ค์ํ ๋ถ๋ถ์
- ๋ฌต์์ ์กฐ์ธ์ ์กฐ์ธ์ด ์ผ์ด๋๋ ์ํฉ์ ํ๋์ ํ์ ํ๊ธฐ ์ด๋ ค์
ํ์น ์กฐ์ธ(fetch join)
- SQL ์กฐ์ธ ์ข ๋ฅ๊ฐ ์๋๋ผ JPQL์์ ์ฑ๋ฅ ์ต์ ํ๋ฅผ ์ํด ์ ๊ณตํ๋ ๊ธฐ๋ฅ
- ์ฐ๊ด๋ ์ํฐํฐ๋ ์ปฌ๋ ์ ์ SQL ํ ๋ฒ์ผ๋ก ํจ๊ป ์กฐํํ๋ ๊ธฐ๋ฅ
- join fetch ๋ช ๋ น์ด ์ฌ์ฉ
- ํ์น ์กฐ์ธ ::= [ LEFT [OUTER] | INNER ] JOIN FETCH ์กฐ์ธ๊ฒฝ๋ก
์ํฐํฐ ํ์น ์กฐ์ธ
ํ์์ ์กฐํํ๋ฉด์ ์ฐ๊ด๋ ํ๋ ํจ๊ป ์กฐํํ๊ณ ์ถ์ ๋
select m from Member m join fetch m.team // JPQL
SELECT M.*, T.* FROM MEMBER M // SQL
INNER JOIN TEAM T ON M.TEAM_ID=T.ID
m๋ง ์กฐํํ์ง๋ง, ํ๋ ๋ค๊ฐ์ด ๊ฐ์ ธ์จ๋ค.
Team team = new Team();
team.setName("๋ก์๋ง์๋ฐฉ๋ฒ๋");
em.persist(team);
Team team2 = new Team();
team2.setName("์ฝฉ์๋ง์๋ฐฉ๋ฒ๋");
em.persist(team2);
Member member1 = new Member();
member1.setUsername("์งฑ๊ตฌ");
member1.addTeam(team);
em.persist(member1);
Member member2 = new Member();
member2.setUsername("๋งน๊ตฌ");
member2.addTeam(team);
em.persist(member2);
Member member3 = new Member();
member3.setUsername("์ฒ ์");
member3.addTeam(team2);
em.persist(member3);
em.flush();
em.clear();
List<Member> members = em.createQuery("select m from Member m join fetch m.team t", Member.class).getResultList();
for (Member member : members) {
System.out.println("memberName = " + member.getUsername());
System.out.println("teamName = " + member.getTeam().getName());
}
fetch join์ ํ๋ฉด ํ์์ ํ์ด ํ๋ก์๊ฐ ์๋๋ผ ์ค์ ๊ฐ์ฒด์ด๊ธฐ ๋๋ฌธ์ ์ถ๊ฐ ์ฟผ๋ฆฌ๋ฌธ์ด ๋ฐ์ํ์ง ์๋๋ค. ์ง์ฐ ๋ก๋ฉ๋ณด๋ค ํ์น ์กฐ์ธ์ด ์ฐ์ ์ด๋ค.
์ปฌ๋ ์ ํ์น ์กฐ์ธ
์ผ๋๋ค ํ์น ์กฐ์ธ์ด๋ฏ๋ก ์ค๋ณต์ด ๋ฐ์ํ๋ค.
select t from Team t join fetch t.members where t.name = 'ํA' // JPQL
SELECT T.*, M.* // SQL
FROM TEAM T
INNER JOIN MEMBER M ON T.ID=M.TEAM_ID
WHERE T.NAME = 'ํA'
Team team1 = new Team();
team1.setName("๋ก์๋ง์๋ฐฉ๋ฒ๋");
em.persist(team1);
Team team2 = new Team();
team2.setName("์ฝฉ์๋ง์๋ฐฉ๋ฒ๋");
em.persist(team2);
Member member1 = new Member();
member1.setUsername("์งฑ๊ตฌ");
member1.addTeam(team1);
em.persist(member1);
Member member2 = new Member();
member2.setUsername("๋งน๊ตฌ");
member2.addTeam(team1);
em.persist(member2);
Member member3 = new Member();
member3.setUsername("์ฒ ์");
member3.addTeam(team2);
em.persist(member3);
em.flush();
em.clear();
List<Team> teams = em.createQuery("select t from Team t join fetch t.members where t.name = '๋ก์๋ง์๋ฐฉ๋ฒ๋'", Team.class).getResultList();
for (Team team : teams) {
System.out.println("teamName = " + team.getName());
for (Member member : team.getMembers()) {
System.out.println("memberName = " + member.getUsername());
}
}
ํ ๋ฒ์ ์์๋ ์๋์ผ๋ก ์ค๋ณต์ด ์๋ต๋๋ค.
ํ์น ์กฐ์ธ๊ณผ DISTINCT
JPQL์ DISTINCT 2๊ฐ์ง ๊ธฐ๋ฅ ์ ๊ณต
- SQL์ DISTINCT๋ฅผ ์ถ๊ฐ
- ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ํฐํฐ ์ค๋ณต ์ ๊ฑฐ
ํ์น ์กฐ์ธ๊ณผ ์ผ๋ฐ ์กฐ์ธ์ ์ฐจ์ด
์ผ๋ฐ ์กฐ์ธ
์ผ๋ฐ ์กฐ์ธ ์คํ์ JPQL์ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ ๋ ์ฐ๊ด๊ด๊ณ๋ฅผ ๊ณ ๋ คํ์ง ์๊ณ , ๋จ์ง SELECT ์ ์ ์ง์ ํ ์ํฐํฐ๋ง ๊ฐ์ ธ์ฌ ๋ฟ์ด๋ค. ์๋ ๊ฒฝ์ฐ์ ํ ์ํฐํฐ๋ง ๊ฐ์ ธ์ค๊ณ , ํ์ ์ํฐํฐ๋ ๊ฐ์ ธ์ค์ง ์๋๋ค.
ํ์น ์กฐ์ธ
ํ์น ์กฐ์ธ์ ์ฌ์ฉํ ๋๋ง ์ฐ๊ด๋ ์ํฐํฐ๋ ํจ๊ป ๊ฐ์ ธ์จ๋ค(์ฆ์ ๋ก๋ฉ). ํ์น ์กฐ์ธ์ ๊ฐ์ฒด ๊ทธ๋ํ๋ฅผ SQL ํ๋ฒ์ผ๋ก ๊ฐ์ ธ์ค๋ ๊ฐ๋ ์ด๋ค.
ํ์น ์กฐ์ธ์ ํน์ง๊ณผ ํ๊ณ
๊ฐ์ฒด ๊ทธ๋ํ๋ ๊ธฐ๋ณธ์ ์ผ๋ก Team์์ members์ ์ ๊ทผํ ๋, ๋ค ์กฐํ๋๋ ๊ฒ์ ๋ชฉ์ ์ผ๋ก ํ๋ค.
- ํ์น ์กฐ์ธ ๋์์๋ ๋ณ์นญ์ ์ค ์ ์๋ค. ํ์ด๋ฒ๋ค์ดํธ๋ ๊ฐ๋ฅํ์ง๋ง, ๊ฐ๊ธ์ ์ด๋ฉด ์ฌ์ฉํ์ง ์๋ ๊ฒ์ ๊ถ์ฅํ๋ค.
select t from Team t join fetch t.members m
select t from Team t join fetch t.members
- ๋ ์ด์์ ์ปฌ๋ ์ ์ ํ์น ์กฐ์ธํ ์ ์๋ค. ์ผ๋๋ค+๋ค๋๋ค
- ์ปฌ๋ ์
์ ํ์น ์กฐ์ธํ๋ฉด ํ์ด์ง API(setFirstResult, setMaxResults)๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
- ์ผ๋์ผ, ๋ค๋์ผ ๊ฐ์ ๋จ์ผ ๊ฐ ์ฐ๊ด ํ๋๋ค์ ํ์น ์กฐ์ธํด๋ ํ์ด์ง ๊ฐ๋ฅ
- ์ปฌ๋ ์ ํ์น ์กฐ์ธ์ ์์ ์์์ setMaxResults๋ฅผ 1๋ก ์ง์ ํ ๋, ํA์ ํ์2๊ฐ ๋ฐ์์ด ์๋๋ ๋ฌธ์ ๊ฐ ๋ฐ์.
- ํ์ด๋ฒ๋ค์ดํธ๋ ๊ฒฝ๊ณ ๋ก๊ทธ๋ฅผ ๋จ๊ธฐ๊ณ ๋ฉ๋ชจ๋ฆฌ์์ ํ์ด์ง(๋งค์ฐ ์ํ)
์ปฌ๋ ์ ํ์น ์กฐ์ธ ํด๊ฒฐ
์์ ๋ฐ๊พธ๊ธฐ
select t from Team t join fetch t.members
=> select m from Member m join fetch m.team t
BatchSize ์ง์
<property name="hibernate.default_batch_fetch_size" value="100"/>
List<Team> teams = em.createQuery("select t from Team t", Team.class).setFirstResult(0).setMaxResults(2).getResultList();
System.out.println("result size = " + teams.size());
for (Team team : teams) {
System.out.println("teamName = " + team.getName());
for (Member member : team.getMembers()) {
System.out.println("memberName = " + member.getUsername());
}
}
team๋ง๋ค members๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ํด ์ฟผ๋ฆฌ๋ฌธ์ ๋ team ์๋งํผ ๋ณด๋ด์ผ ํ๋ค. BatchSize๋ฅผ ์ง์ ํ๋ฉด, members์ ๊ด๋ จ๋ TEAM_ID ๋ฟ๋ง ์๋๋ผ ๋ค๋ฅธ TEAM_ID๋ค๋ ์ง์ ํ size๋งํผ ๊ฐ์ด ํ ์ฟผ๋ฆฌ๋ฌธ์ ์ง์ ํด์ ๋ณด๋ด๊ธฐ ๋๋ฌธ์ ์ต์ข ์ ์ผ๋ก ๋ณด๋ด๊ฒ ๋๋ ์ฟผ๋ฆฌ๋ฌธ์ ์๊ฐ ์ค์ด๋ค๊ฒ ๋๋ค.
์ ๋ฆฌ
- ํ์น ์กฐ์ธ์ ๊ฐ์ฒด ๊ทธ๋ํ๋ฅผ ์ ์งํ๋ฉด์ ์ฐพ์๊ฐ์ผํ ๋ ์ฌ์ฉํ๋ฉด ํจ๊ณผ์
- ์ฌ๋ฌ ํ ์ด๋ธ์ ์กฐ์ธํด์ ์ํฐํฐ๊ฐ ๊ฐ์ง ๋ชจ์์ด ์๋ ์ ํ ๋ค๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ๋ด์ผ ํ๋ฉด, ํ์น ์กฐ์ธ๋ณด๋ค๋ ์ผ๋ฐ ์กฐ์ธ์ ์ฌ์ฉํ๊ณ ํ์ํ ๋ฐ์ดํฐ๋ค๋ง ์กฐํํด์ DTO๋ก ๋ฐํํ๋ ๊ฒ์ด ํจ๊ณผ์
๋คํ์ฑ ์ฟผ๋ฆฌ
Type
์กฐํ ๋์์ ํน์ ์์์ผ๋ก ํ์
// Item ์ค์ Book, Movie๋ฅผ ์กฐํํด๋ผ
select i from Item i where type(i) IN (Book, Movie)
Treat
์๋ฐ์ ํ์ ์บ์คํ ๊ณผ ์ ์ฌํ๋ฉฐ ์์ ๊ตฌ์กฐ์์ ๋ถ๋ชจ ํ์ ์ ํน์ ์์ ํ์ ์ผ๋ก ๋ค๋ฃฐ ๋ ์ฌ์ฉํ๋ค.
select i from Item i where treat(i as Book).author = ‘kim’
์ํฐํฐ ์ง์ ์ฌ์ฉ
- JPQL์์ ์ํฐํฐ๋ฅผ ์ง์ ์ฌ์ฉํ๋ฉด SQL์์ ํด๋น ์ํฐํฐ์ ๊ธฐ๋ณธ ํค ๊ฐ์ ์ฌ์ฉ
select count(m) from Member m //์ํฐํฐ๋ฅผ ์ง์ ์ฌ์ฉ
==
select count(m.id) from Member m //์ํฐํฐ์ ์์ด๋๋ฅผ ์ฌ์ฉ
String jpql = “select m from Member m where m = :member”;
List resultList = em.createQuery(jpql).setParameter("member", member).getResultList();
==
String jpql = “select m from Member m where m.id = :memberId”;
List resultList = em.createQuery(jpql).setParameter("memberId", memberId).getResultList();
Member findMember = em.createQuery("select m from Member m where m=:member", Member.class).setParameter("member", member1).getSingleResult();
System.out.println("findMember.getUsername() = " + findMember.getUsername());
where์ id ์กฐ๊ฑด์ผ๋ก ์ถ๊ฐ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
- ์ธ๋ํค ๊ฐ์ผ๋ก ์ฌ์ฉํ๋ ๊ฒฝ์ฐ
List<Member> resultList = em.createQuery("select m from Member m where m.team = :team", Member.class).setParameter("team", team1).getResultList();
for (Member member : resultList) {
System.out.println("memberName = " + member.getUsername());
}
List<Member> resultList = em.createQuery("select m from Member m where m.team.id = :teamId", Member.class).setParameter("teamId", team1.getId()).getResultList();
for (Member member : resultList) {
System.out.println("memberName = " + member.getUsername());
}
m.team์ด ์ธ๋ํค ๊ฐ์ผ๋ก ์ฌ์ฉ๋๋ค.
Named ์ฟผ๋ฆฌ
- ๋ฏธ๋ฆฌ ์ ์ํด์ ์ด๋ฆ์ ๋ถ์ฌํด๋๊ณ ์ฌ์ฉํ๋ JPQL
- ์ ์ ์ฟผ๋ฆฌ
- ์ด๋ ธํ ์ด์ , XML์ ์ ์
- ์ ํ๋ฆฌ์ผ์ด์ ๋ก๋ฉ ์์ ์ JPQL์ ๊ฒ์ฆํ๊ณ , SQL๋ก ์ด๊ธฐํํจ. ์ดํ์๋ ์ฌ์ฌ์ฉ
@Entity
@NamedQuery(
name = "Member.findByUsername",
query = "select m from Member m where m.username = :username" // Member๊ฐ ์๋๋ผ Memberr์ด๋ฉด ์ค๋ฅ๋ฅผ ๋ฐ์์ํด
)
public class Member {
List<Member> resultList = em.createNamedQuery("Member.findByUsername", Member.class).setParameter("username", "์งฑ๊ตฌ").getResultList();
for (Member member : resultList) {
System.out.println("member.getUsername() = " + member.getUsername());
}
@NamedQuery ๋์ ์คํ๋ง ๋ฐ์ดํฐ JPA๋ฅผ ์ฌ์ฉํ๋ค.
https://spring.io/projects/spring-data-jpa
Spring Data JPA
Spring Data JPA, part of the larger Spring Data family, makes it easy to easily implement JPA-based (Java Persistence API) repositories. It makes it easier to build Spring-powered applications that use data access technologies. Implementing a data access l
spring.io
๋ฒํฌ ์ฐ์ฐ
- ์ฟผ๋ฆฌ ํ ๋ฒ์ผ๋ก ์ฌ๋ฌ ํ ์ด๋ธ ๋ก์ฐ ๋ณ๊ฒฝ
- executeUpdate()์ ๊ฒฐ๊ณผ๋ ์ํฅ๋ฐ์ ์ํฐํฐ ์ ๋ฐํ
- UPDATE, DELETE์ ๋ํ์ฌ ๊ฐ๋ฅ
- INSERT(insert into ... select)๋ ํ์ด๋ฒ๋ค์ดํธ๊ฐ ์ง์ํด์ ๊ฐ๋ฅํ๋ค.
- ๋ฒํฌ ์ฐ์ฐ์ ์์์ฑ ์ปจํ
์คํธ๋ฅผ ๋ฌด์ํ๊ณ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ง์ ์ฟผ๋ฆฌ๋ฅผ ๋ ๋ฆฐ๋ค.
- ์์์ฑ ์ปจํ ์คํธ์ ๊ฐ์ ๋ฃ๊ธฐ ์ ์ ๋ฒํฌ ์ฐ์ฐ์ ๋จผ์ ์คํ
- ์์์ฑ ์ปจํ ์คํธ์ ๊ฐ์ด ์๋ค๋ฉด ๋ฒํฌ ์ฐ์ฐ ์ํ ํ ์์์ฑ ์ปจํ ์คํธ๋ฅผ ์ด๊ธฐํ ์ํจ๋ค.
Team team1 = new Team();
team1.setName("๋ก์๋ง์๋ฐฉ๋ฒ๋");
em.persist(team1);
Team team2 = new Team();
team2.setName("์ฝฉ์๋ง์๋ฐฉ๋ฒ๋");
em.persist(team2);
Member member1 = new Member();
member1.setUsername("์งฑ๊ตฌ");
member1.addTeam(team1);
em.persist(member1);
Member member2 = new Member();
member2.setUsername("๋งน๊ตฌ");
member2.addTeam(team1);
em.persist(member2);
Member member3 = new Member();
member3.setUsername("์ฒ ์");
member3.addTeam(team2);
em.persist(member3);
int resultCount = em.createQuery("update Member m set m.age = 20").executeUpdate();
System.out.println("resultCount = " + resultCount);
em.clear();
createQuery๋ฅผ ํ๊ธฐ ์ ์ flush๊ฐ ํธ์ถ๋์ด Member์ Team ์ ๋ณด๊ฐ DB์ ๋ฐ์๋์ด ์๋ค. ๋ฒํฌ ์ฐ์ฐ์ ์ํํ๋ฉด, ์์์ฑ ์ปจํ ์คํธ๋ ๋ฌด์ํ๊ณ , ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ฐ๋ง ๋ณ๊ฒฝํ๊ธฐ ๋๋ฌธ์ ์์์ฑ ์ปจํ ์คํธ์์๋ ๋์ด๊ฐ 20์ด๋ก ๋ฐ์๋์ง ์๋๋ค. ์ด๋ em.clear()๋ฅผ ํด์ฃผ๋ฉด, ์์์ฑ ์ปจํ ์คํธ์ ์๋ ๊ฒ๋ค์ด ๋ชจ๋ ์ฌ๋ผ์ง๊ณ , ๋ค์์ ํธ์ถํ ๋ DB์์ ๋ฐ์์ค๋ฏ๋ก ์ ๋ฐ์ดํธ๊ฐ ๋ฐ์๋ ์ ๋ณด๋ฅผ ์ป๋๋ค.
๊ธฐ์ตํ๋ฉด ์ข์ ๊ฒ
- ์ฐ๊ด๊ด๊ณ ์ฃผ์ธ์ ๋ค ์ชฝ, ์ธ๋ํค๋ฅผ ์ ์ฅํ๋ ์ชฝ์ ํ๋์ ์ค์ ํ๊ณ , ์ฐ๊ด๊ด๊ณ ๋ฉ์๋๋ ์ํฅ๋ ฅ์ ์์ํ๋ ๋ถ๋ถ์ ์ค์ ํ๋ค.
- ๊ฐ ํ์ ์ปฌ๋ ์ ์ ๋งค์ฐ ๊ฐ๋จํ ๊ฒฝ์ฐ๊ฐ ์๋๋ฉด ์ฌ์ฉํ์ง ์๋๋ค. ๊ฐ ํ์ ์ ์ ๋ง ๊ฐ ํ์ ์ด๋ผ ํ๋จ๋ ๋๋ง ์ฌ์ฉ
- ์๋ณ์๊ฐ ํ์ํ๊ณ , ์ง์ํด์ ๊ฐ์ ์ถ์ , ๋ณ๊ฒฝํด์ผ ํ๋ค๋ฉด ๊ทธ๊ฒ์ ๊ฐ ํ์ ์ด ์๋ ์ํฐํฐ
- ์์์ฑ ์ปจํ ์คํธ์ ์๋ ๊ฐ์ฒด์ ๋ํ ์ ๋ณด๋ฅผ ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋ณ๊ฒฝํ๋ฉด ๋ํฐ์ฒดํน์ ์ํด ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ณ๊ฒฝ๋ ์ ๋ณด๊ฐ ๋ฐ์๋์ง๋ง, ๋ฒํฌ ์ฐ์ฐ์ผ๋ก ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๋ณ๊ฒฝํ๋ฉด ์์์ฑ ์ปจํ ์คํธ์ ์๋ ๊ฐ์ฒด๋ ์ํฅ์ ๋ฐ์ง ์๋๋ค.
'๐๐ปโโ๏ธ ๊ธฐ๋ณธํ๋ จ > Java' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[๋ชจ๋ ์๋ฐ ์ธ ์ก์ ] ๋์ ํ๋ผ๋ฏธํฐํ ์ฝ๋ ์ ๋ฌํ๊ธฐ (0) | 2024.09.03 |
---|---|
[Java] ์๋ฐ ๊ธฐ์ด (0) | 2024.08.27 |
[JPA] ์๋ช ์ฃผ๊ธฐ ์ผ์น ์ ์ฐธ์กฐ ๋ณ๊ฒฝ์ ์ํ์ฑ (0) | 2024.08.19 |
[JPA] not connection (0) | 2024.07.28 |
[Java] ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ฐธ์กฐ (0) | 2024.07.27 |