๐คญ ๋ฏธ๋ฆฌ ์ฝ๊ณ ์ค๋ฉด ์ข์ ๊ธ
1๏ธโฃ ์์์ฑ ์ปจํ ์คํธ๋?
์์์ฑ ์ปจํ ์คํธ๋ ์ํฐํฐ๋ฅผ ์๊ตฌ ์ ์ฅํ๋ ํ๊ฒฝ์ ๋ปํ๋ฉฐ ์ ํ๋ฆฌ์ผ์ด์ ๊ณผ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฌ์ด์์ ๊ฐ์ฒด๋ฅผ ๋ณด๊ดํ๋ ๊ฐ์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ฐ์ ์ญํ ์ ํ๋ค. ์ํฐํฐ ๋งค๋์ ๋ฅผ ํตํด ์ํฐํฐ๋ฅผ ์ ์ฅํ๊ฑฐ๋ ์กฐํํ๋ฉด ์ํฐํฐ ๋งค๋์ ๋ ์์์ฑ ์ปจํ ์คํธ ํ ๊ฐ๋ฅผ ๋ง๋ค์ด ์ํฐํฐ๋ฅผ ๋ณด๊ดํ๊ณ ๊ด๋ฆฌํ๋ค.
em.persist(member); // "์ํฐํฐ ๋งค๋์ ๋ฅผ ์ด์ฉํด ํ์ ์ํฐํฐ๋ฅผ ์์์ฑ ์ปจํ
์คํธ์ ์ ์ฅํ๋ค"๋ ์๋ฏธ
2๏ธโฃ ์์์ฑ ์ปจํ ์คํธ์ ๋์์๋ฆฌ
๐ฑ member ์ํฐํฐ๋ฅผ ์ถ๊ฐํ๋ ๊ณผ์
1. ์ํฐํฐ๊ฐ ์์ํ(persist)๋์ด 1์ฐจ ์บ์์ ์ ์ฅ๋๋ค.
2. ์ฐ๊ธฐ์ง์ฐ SQL ์ ์ฅ์์ INSERT๋ฌธ์ด ์์ฑ๋์ด 1์ฐจ ์บ์์ ๋ฑ๋ก๋ ๋ฐ์ดํฐ๋ฅผ DB ํ ์ด๋ธ์ ์ถ๊ฐํ ์ค๋น๋ฅผ ํ๋ค.
3. flush ๋ช ๋ น ์ ์ฐ๊ธฐ์ง์ฐ SQL ์ ์ฅ์์ ์ ์ฅ๋์ด ์๋ ์ฟผ๋ฆฌ๋ค์ด ์คํ๋๋ฉด์ 1์ฐจ ์บ์์ DB๊ฐ ๋๊ธฐํ๋๋ค.
4. ๋ง์ง๋ง์ผ๋ก commit๊น์ง ์๋ฃ๋๋ฉด 1์ฐจ ์บ์์ ๋ด์ฉ์ด ์์ ํ DB์ ๋ฐ์๋๋ค.
์ ์์ ์ ๋ชจ๋ ๋จ์ผํ ํธ๋์ญ์ ๋ด์์ ์ผ์ด๋๋ค.
์์์ฑ ์ปจํ ์คํธ๋ ํธ๋์ญ์ ๋ด์์ ์ผ์ด๋๋ ์์ ์ ๋ชจ๋ ๊ธฐ๋กํ๋ ๊ณต๊ฐ์ด๋ฉฐ, ๋ชจ๋ ์์ ์ ์ธ์ ๋ ROLLBACK ๋ ์ ์๋ค.
3๏ธโฃ ์์์ฑ ์ปจํ ์คํธ ๋ฒ์
ํธ๋์ญ์ ์ด ๊ฐ์ผ๋ฉด, ๊ฐ์ ์์์ฑ ์ปจํ ์คํธ๋ฅผ ์ฌ์ฉํ๋ค.
ํธ๋์ญ์ ๋ฒ์์ ์์์ฑ ์ปจํ ์คํธ ์ ๋ต์ ๋ค์ํ ์์น์์ ์ํฐํฐ ๋งค๋์ ๋ฅผ ์ฃผ์ ๋ฐ์ ์ฌ์ฉํ๋๋ผ๋, ๋์ผํ ํธ๋์ญ์ ๋ด์์๋ ํญ์ ๊ฐ์ ์์์ฑ ์ปจํ ์คํธ๋ฅผ ์ฌ์ฉํ๋ค.
@Repository
class Repo1 {
@PersistenceContext EntityManager em;
public void logic1(){
em.xxx(); // Repo1์ ์์์ฑ ์ปจํ
์คํธ ์ ๊ทผ
}
}
@Repository
class Repo2 {
@PersistenceContext EntityManager em;
public void logic2(){
em.xxx(); // Repo2์ ์์์ฑ ์ปจํ
์คํธ ์ ๊ทผ
}
}
์์ ๊ฐ์ ์ํฉ์์ ์๋ logic()์ ์คํํ๋ ์ํฉ์ ์๋ก ๋ค๋ฉด
@Service
class MainService{
@Autowired Repo1 repo1;
@Autowired Repo2 repo2;
@Transctional
public void logic(){
repo1.logic1();
repo2.logic2();
}
}
repo1๊ณผ repo2์ ์ํฐํฐ ๋งค๋์ ๋ ๋ค๋ฅด์ง๋ง, ๊ฐ์ ํธ๋์ญ์ ์ด๊ธฐ ๋๋ฌธ์ ๊ฐ์ ์์์ฑ ์ปจํ ์คํธ๋ฅผ ์ฌ์ฉํ๋ค.
๊ทธ๋ฆฌ๊ณ ํด๋น ์์์ฑ ์ปจํ ์คํธ๋ ํธ๋์ญ์ ๊ณผ ์๋ช ์ฃผ๊ธฐ๊ฐ ๋์ผํ๋ค.
ํธ๋์ญ์ ์ด ๋ค๋ฅด๋ฉด, ๋ค๋ฅธ ์์์ฑ ์ปจํ ์คํธ๋ฅผ ์ฌ์ฉํ๋ค.
์คํ๋ง ์ปจํ ์ด๋๋ ์ค๋ ๋๋ง๋ค ๊ฐ๊ฐ ๋ค๋ฅธ ํธ๋์ญ์ ์ ํ ๋นํ๊ธฐ ๋๋ฌธ์ ๊ฐ์ ์ํฐํฐ ๋งค๋์ ๋ฅผ ์ฌ์ฉํด๋ ๋ค๋ฅธ ์์์ฑ ์ปจํ ์คํธ๋ฅผ ์ฌ์ฉํ๋ค.
๋ฐ๋ผ์ ์์์ฑ ์ปจํ ์คํธ๊ฐ ์ค๋ ๋ ๊ฐ์ ๊ณต์ ๋์ง ์์ผ๋ฏ๋ก ๋ฉํฐ์ค๋ ๋ ์ํฉ์ ์์ ํ๋ค.
4๏ธโฃ ์์์ฑ ์ปจํ ์คํธ์ ์ด์
- 1์ฐจ ์บ์
- ๋์ผ์ฑ ๋ณด์ฅ
- ๋ณ๊ฒฝ ๊ฐ์ง(Dirty Checking)
- ์ฐ๊ธฐ ์ง์ฐ
- ์ง์ฐ ๋ก๋ฉ
1) 1์ฐจ ์บ์
๐ฑ member ์ํฐํฐ๋ฅผ ์กฐํํ๋ ๊ณผ์
1. EntityManager๊ฐ ์กฐํ(find)๋ฅผ ์์ฒญํ๋ค.
2. 1์ฐจ ์บ์์์ ์ฐ์ ์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ฐพ๊ณ ์ํ๋ ๋ฐ์ดํฐ๊ฐ ์๋ ๊ฒฝ์ฐ DB SELECT๋ฌธ์ ์คํํ์ฌ ์กฐํํ๋ค.
3. ์กฐํํ ๊ฒฐ๊ณผ๋ฅผ 1์ฐจ ์บ์์ ์ ์ฅํ๊ณ ์ํฐํฐ ๊ฐ์ฒด๋ฅผ ์์ฑํ์ฌ ๋ฐํ(return)ํ๋ค.
์ดํ ๋จ์ผ ํธ๋์ญ์ ์์ ๊ฐ์ ์ํฐํฐ๋ฅผ ์กฐํํ ๊ฒฝ์ฐ 1์ฐจ ์บ์์์ ๋ฐ๋ก ์ํฐํฐ ์กฐํ๊ฐ ๊ฐ๋ฅํ๋ค.
์ด๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ ๊ทผ์ ์ค์ฌ ์ฑ๋ฅ์ ํฅ์์ํจ๋ค.
2) ๋์ผ์ฑ ๋ณด์ฅ
1์ฐจ ์บ์๋ flush๊ฐ ์ํ๋์ง ์๋ ์ด์ DB์ ๋๊ธฐํ๋์ง ์๋๋ค. ๋ฐ๋ผ์ 1์ฐจ ์บ์์ ์กด์ฌํ๋ ์ํฐํฐ๋ ์ธ์ ๋ ๋์ผํ ์ํฐํฐ์ด๋ค.
Member findMember1 = em.find(Member.class, 10L);
Member findMember2 = em.find(Member.class, 10L);
System.out.println("findMember = " + (findMember1 == findMember2));
๋ฐ๋ผ์ ๊ฐ์ ํธ๋์ญ์ ์์์ == ๋น๊ต ์ ๋์ผํ ์ฐธ์กฐ๊ฐ ๋์ true๋ฅผ ๋ฐํํ๋ค.
3) ์ฐ๊ธฐ ์ง์ฐ
์์ ์์์ฑ ์ปจํ ์คํธ์ ๋์ ์๋ฆฌ์์ ์ค๋ช ํ๋ฏ์ด ์์์ฑ ์ปจํ ์คํธ๋ ์ฐ๊ธฐ์ง์ฐ SQL ์ ์ฅ์๋ฅผ ๊ฐ์ ธ SQL๋ฌธ์ด ์์ฑ๋์ด๋ ๋ฐ๋ก ์คํ๋์ง ์๊ณ ์ ์ฅ๋๋ค. ๋ฐ๋ผ์ ์ฆ์ I/O ๋ฐ์์ ๋ง์ ์ ์๋ค.
๋, ์ํ๋ ์์ ์ ๊ฐ๋ฐ์๊ฐ SQL๋ฌธ์ ์คํํ ์ ์๋๋ก flush ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค.
๐ค flush๊ฐ ํธ์ถ๋๋ ๊ฒฝ์ฐ
- entitymanager.flush(): ๊ฐ๋ฐ์๊ฐ ์ง์ ํธ์ถ
- tx.commit(): ์๋ ์คํ
- ์ปค๋ฐ ์ ์ ์ฅ์์ ์๋ SQL๋ฌธ๋ค์ flush ํ์ฌ ์คํ์ํจ ํ, DB์ ๋ฐ์ํ๋ค.
- JPQL ์ฟผ๋ฆฌ ์คํ: ์๋ ์คํ
- JPQL์ JPA ๋ง์ถค SQL ์ฟผ๋ฆฌ๋ฌธ์ด๋ค. JPQL์ EntityManager๊ฐ ์คํํ๋ ์ฟผ๋ฆฌ๋ก ํ์ฑ ๋์ด SQL๋ฌธ์ผ๋ก ๋ณํ๋์ด ์ฐ๊ธฐ์ง์ฐ SQL ์ ์ฅ์์ ์ ์ฅ๋์ง ์๊ณ ๋ฐ๋ก DB์ ์คํ๋๋ค.
๋ฐ๋ผ์ ์ด์ ์ ์ฐ๊ธฐ์ง์ฐ SQL ์ ์ฅ์์ ์ ์ฅํ๋ SQL๋ฌธ๋ค์ ๋จผ์ flush ํด์ผ ๋ฐ์ดํฐ์ ๋ฌธ์ ๊ฐ ์๊ธฐ์ง ์๋๋ค.
- JPQL์ JPA ๋ง์ถค SQL ์ฟผ๋ฆฌ๋ฌธ์ด๋ค. JPQL์ EntityManager๊ฐ ์คํํ๋ ์ฟผ๋ฆฌ๋ก ํ์ฑ ๋์ด SQL๋ฌธ์ผ๋ก ๋ณํ๋์ด ์ฐ๊ธฐ์ง์ฐ SQL ์ ์ฅ์์ ์ ์ฅ๋์ง ์๊ณ ๋ฐ๋ก DB์ ์คํ๋๋ค.
4) ๋ณ๊ฒฝ ๊ฐ์ง(Dirty Checking)
์์์ฑ ์ปจํ ์คํธ๋ 1์ฐจ ์บ์์ ์ ์ฅ๋ ์ํฐํฐ์ ์ฒ์ ์ํ๋ฅผ ์ค๋ ์ท์ผ๋ก ๋ง๋ค์ด ์ ์ฅํ๋ค.
๐ฑ member ์ํฐํฐ๋ฅผ ์์ ํ๋ ๊ณผ์
1. ๊ฐ๋ฐ์๊ฐ find()๋ก ์ํฐํฐ๋ฅผ ์กฐํํ๋ค.
2. ๊ฐ๋ฐ์๊ฐ ํด๋น ์ํฐํฐ๋ฅผ setter ํจ์๋ก ํ๋ ๋ฐ์ดํฐ๋ฅผ ๋ณ๊ฒฝํ๋ค.
โ๏ธ ์ฒ์ ์ํ์ ์ค๋ ์ท๊ณผ ๋์ผํ๋ ๊ณผ๊ฑฐ์ ๋ฌ๋ฆฌ, ๋๋ฝํ์ก๋ค.(Dirty)
์์์ฑ ์ปจํ ์คํธ๋ ์ด๊ธฐ ์ํ๋ฅผ ์ ์ฅํ ์ค๋ ์ท๊ณผ ์ํฐํฐ๋ฅผ ๋น๊ตํ์ฌ ์ผ๋ง๋ ๋๋ฌ์์ก๋์ง๋ฅผ ์ฒดํฌํ๋๋ฐ, ์ด๋ฅผ Dirty Checking ์ฆ, ๋ณ๊ฒฝ๊ฐ์ง๋ผ ๋ถ๋ฅธ๋ค.
๋ณ๊ฒฝ์ด ๊ฐ์ง๋๋ฉด ์์์ฑ ์ปจํ ์คํธ๋ ์๋์ผ๋ก UPDATE๋ฌธ์ ์์ฑํ์ฌ ์ฐ๊ธฐ์ง์ฐ SQL ์ ์ฅ์์ ์ ์ฅํ๋ค.
๊ฐ๋ฐ์๋ ๋จ์ํ ํ๋ ๋ฐ์ดํฐ๋ง ๋ณ๊ฒฝํ ๊ฒ์ธ๋ฐ ์๋์ผ๋ก UPDATE๋ฌธ๊น์ง ์์ฑ๋์ด ์์ฌ์ด ๊ฐ๋ฐ์ด ๊ฐ๋ฅํด์ง๋ค.
5) ์ง์ฐ ๋ก๋ฉ(Lazy Loading)
๐ฑ ์ฆ์ ๋ก๋ฉ(Eager Loading)
์ฐ๊ด ๊ด๊ณ ๋งคํ์ fetch ์์ฑ์ FetchType.EAGER๋ก ์ง์ ํด ์ํฐํฐ ์กฐํ ์ ์ฐ๊ด๋ ์ํฐํฐ๋ฅผ ํจ๊ป ์กฐํํ๋ค.
public class Member {
...
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "TEAM_ID")
private Team team;
}
SELECT
...
FROM
MEMBER M LEFT OUTER JOIN TEAM T
ON M.TEAM_ID=T.TEAM_ID
WHERE
M.MEMBER_ID="id"
ํ์ด๋ฒ๋ค์ดํธ๋ ์ฆ์ ๋ก๋ฉ์ ์ต์ ํํ๊ธฐ ์ํด ๊ฐ๋ฅํ๋ฉด ์กฐ์ธ ์ฟผ๋ฆฌ๋ฅผ ํตํด ์ฐ๊ด ์ํฐํฐ๋ฅผ ํ ๋ฒ์ ์กฐํํ๋ค.
์ด๋, ์คํ๋๋ SQL์ ์ธ๋ถ ์กฐ์ธ(LEFT OUTER JOIN)์ ์ฌ์ฉํ๋ค. (ํ์์ ํ์ด ์์ ์ ์์ด NULL๊ฐ์ ํ์ฉํ๊ธฐ ๋๋ฌธ)
ํ์ง๋ง ์ฑ๋ฅ ์ต์ ํ์์๋ ๋ด๋ถ ์กฐ์ธ(INNER JOIN)์ด ์ ๋ฆฌํ๊ธฐ ๋๋ฌธ์ @JoinColumn(nullable = false)๋ฅผ ์ฌ์ฉํ๋ฉด ๋ด๋ถ ์กฐ์ธ์ ์ฌ์ฉํ ์ ์๋ค.
๐ฑ ์ง์ฐ ๋ก๋ฉ(Lazy Loading)
์ฐ๊ด ๊ด๊ณ ๋งคํ์ fetch ์์ฑ์ FetchType.LAZY๋ก ์ง์ ํด ์ฐ๊ด๋ ์ํฐํฐ๋ฅผ ์ค์ ๋ก ์ฌ์ฉํ ๋ ์กฐํํ๋ค.
@Entity
public class Member {
...
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TEAM_ID")
private Team team;
}
ํ์ ์กฐํ ์ ๋ฐ๋ก ํ์ ์กฐํํ์ง ์๊ณ , team ๋ฉค๋ฒ ๋ณ์์ ํ๋ก์ ๊ฐ์ฒด(๊ฐ์ง ๊ฐ์ฒด)๋ฅผ ๋ฃ์ด๋๋ค.
๊ทธ ํ team์ ์ค์ ๋ฐ์ดํฐ๊ฐ ํ์ํ ์๊ฐ์ DB๋ฅผ ์กฐํํด ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์กฐํํ๋ค.
๋ง์ฝ ์์์ฑ ์ปจํ ์คํธ์ ๊ฐ์ฒด๊ฐ ์ด๋ฏธ ์กด์ฌํ ๊ฒฝ์ฐ ํ๋ก์ ๊ฐ์ฒด๊ฐ ์๋ ์ค์ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๋ค.
์ถ์ฒํ๋ ๋ฐฉ๋ฒ์ ๋ชจ๋ ์ฐ๊ด๊ด๊ณ์ ์ง์ฐ ๋ก๋ฉ์ ์ฌ์ฉํ๋ ๊ฒ์ด์ง๋ง ์ง์ฐ ๋ก๋ฉ์ด ํญ์ ์ข์ ๊ฒ์ ์๋๋ค.
๋ง์ฝ ํ๊ณผ ํ์์ ํญ์ ํจ๊ป ์ฌ์ฉํ๋ค๋ฉด ์ฒ์๋ถํฐ ํ ๋ฒ์ ๊ฐ์ ธ์ค๋ ๊ฒ์ด ํจ์จ์ ์ด๊ธฐ ๋๋ฌธ์ ์ํฉ์ ๋ง๊ฒ ์ ํํ๋ ๊ฒ์ด ์ข๋ค.
๋ฐ๋ผ์ ๊ฐ๋ฐ ์๋ฃ ๋จ๊ณ์ ์์ ๋, ์ค์ ์ฌ์ฉ ์ํฉ์ ๋ณด๋ฉฐ ์ต์ ํํ๋ ๊ฒ์ด ์ข๋ค.
'Back-end' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Spring] Spring REST Docs ๊ถํ ์๋ฌ (2) | 2024.02.29 |
---|---|
[Spring] ์์กด์ฑ ์ฃผ์ ์ @Autowired๋ณด๋ค ์์ฑ์ ์ฃผ์ ์ ๊ถ์ฅํ๋ ์ด์ (0) | 2024.02.28 |
[JPA] OSIV(Open Session In View)๋? (0) | 2023.09.21 |
[JPA] Hibernate Cache๋? (0) | 2023.09.03 |
[Spring] @Transaction(readOnly = true) ์ค์ (0) | 2023.09.01 |