1. ์์์ฑ ์ปจํ ์คํธ์ ์ค์์ ์ํฐํฐ๋?
์์์ฑ ์ปจํ ์คํธ(Persistence Context)
JPA์์๋ ์ํฐํฐ(Entity)๋ฅผ ๊ด๋ฆฌํ๋ ํ๊ฒฝ์ ์์์ฑ ์ปจํ ์คํธ(Persistence Context)๋ผ๊ณ ํฉ๋๋ค.
์์์ฑ ์ปจํ ์คํธ๋ ์ํฐํฐ์ ์๋ช ์ฃผ๊ธฐ๋ฅผ ๊ด๋ฆฌํ๋ฉฐ,
๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๋๊ธฐํ๋ฅผ ์๋์ผ๋ก ์ฒ๋ฆฌํ๋ ์ค์ํ ์ญํ ์ ํฉ๋๋ค.
์ค์์ ์ํฐํฐ(Detached Entity)
์ค์์ ์ํฐํฐ(Detached Entity)๋,
ํ ๋ฒ ์์ ์ํ(Persistent State)์๋ค๊ฐ ํ์ฌ๋ ์์์ฑ ์ปจํ ์คํธ์์ ๊ด๋ฆฌ๋์ง ์๋ ์ํฐํฐ๋ฅผ ์๋ฏธํฉ๋๋ค.
์๋ฅผ ๋ค์ด, ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์กฐํ๋ Book ๊ฐ์ฒด๊ฐ ์กด์ฌํ๋๋ฐ,
ํธ๋์ญ์ ์ด ์ข ๋ฃ๋๊ฑฐ๋ ์์์ฑ ์ปจํ ์คํธ์์ ๋ถ๋ฆฌ๋๋ฉด ํด๋น ๊ฐ์ฒด๋ ์ค์์ ์ํ๊ฐ ๋ฉ๋๋ค.
์ด๋ฌํ ๊ฐ์ฒด๋ฅผ ๋ค์ ์์ ํ๋ ค๋ฉด ๋ณ๊ฒฝ ๊ฐ์ง(Dirty Checking) ๋๋ ๋ณํฉ(Merge) ๊ธฐ๋ฒ์ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
2. ์ค์์ ์ํฐํฐ ์์ ๋ฐฉ๋ฒ
2.1. ๋ณ๊ฒฝ ๊ฐ์ง ๊ธฐ๋ฅ(Dirty Checking) ์ฌ์ฉ
๋ณ๊ฒฝ ๊ฐ์ง๋ ์์์ฑ ์ปจํ ์คํธ๊ฐ ๊ด๋ฆฌํ๋ ์ํฐํฐ๋ฅผ ๋ณ๊ฒฝํ๋ฉด ์๋์ผ๋ก ๊ฐ์งํ์ฌ ์ ๋ฐ์ดํธํ๋ ๊ธฐ๋ฅ์ ๋๋ค.
๋ณ๊ฒฝ ๊ฐ์ง ์์ ์ฝ๋
@Transactional
void update(Item itemParam) { // itemParam: ์ค์์ ์ํ์ ์ํฐํฐ
Item findItem = em.find(Item.class, itemParam.getId()); // ๊ฐ์ ์ํฐํฐ ์กฐํ
findItem.setPrice(itemParam.getPrice()); // ๋ฐ์ดํฐ ์์
}
๋ณ๊ฒฝ ๊ฐ์ง ๋ฐฉ์
- ํธ๋์ญ์ ์์์ ์์ ์ํ์ ์ํฐํฐ๋ฅผ ๋ค์ ์กฐํํฉ๋๋ค.
- ํ์ํ ๊ฐ๋ง ์ ํ์ ์ผ๋ก ๋ณ๊ฒฝํฉ๋๋ค.
- ํธ๋์ญ์ ์ด ์ปค๋ฐ๋๋ ์์ ์ ๋ณ๊ฒฝ ๊ฐ์ง(Dirty Checking)๊ฐ ๋์ํ์ฌ ์๋์ผ๋ก UPDATE SQL์ ์คํํฉ๋๋ค.
2.2. ๋ณํฉ(Merge) ์ฌ์ฉ
๋ณํฉ์ ์ค์์ ์ํ์ ์ํฐํฐ๋ฅผ ์์ ์ํ๋ก ๋ณ๊ฒฝํ๋ ๊ธฐ๋ฅ์ ๋๋ค.
๋ณํฉ ์์ ์ฝ๋
@Transactional
void update(Item itemParam) { // itemParam: ์ค์์ ์ํ์ ์ํฐํฐ
Item mergeItem = em.merge(itemParam);
}
๋ณํฉ ๋์ ๋ฐฉ์
- merge() ์คํ
- ์๋ณ์(ID)๋ฅผ ๊ธฐ์ค์ผ๋ก 1์ฐจ ์บ์์์ ์ํฐํฐ๋ฅผ ์กฐํ
- 1์ฐจ ์บ์์ ์์ผ๋ฉด ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์กฐํ ํ 1์ฐจ ์บ์์ ์ ์ฅ
- ์กฐํ๋ ์์ ์ํ์ ์ํฐํฐ(mergeItem)์ ์ค์์ ์ํฐํฐ์ ๋ฐ์ดํฐ๋ฅผ ๋ชจ๋ ๋ณต์ฌ
- ๋ณํฉ๋ ์์ ์ํ ์ํฐํฐ๋ฅผ ๋ฐํ
๋ณํฉ๊ณผ ๋ณ๊ฒฝ ๊ฐ์ง์ ์ฐจ์ด์
๋ณ๊ฒฝ | ๋ฐฉ์ | ์ฅ์ | ๋จ์ |
๋ณ๊ฒฝ ๊ฐ์ง | ์์ ์ํ์ ์ํฐํฐ๋ฅผ ์ง์ ์์ | ์ํ๋ ์์ฑ๋ง ์ ํ์ ์ผ๋ก ๋ณ๊ฒฝ ๊ฐ๋ฅ | ์ง์ ์ํฐํฐ๋ฅผ ์กฐํํด์ผ ํจ |
๋ณํฉ(Merge) | ์ค์์ ์ํฐํฐ์ ๋ชจ๋ ํ๋๋ฅผ ๋ณต์ฌ | ์๋์ผ๋ก ๋ณํฉ ์ํ | ๋ชจ๋ ํ๋๊ฐ ๋ฎ์ด์์์ง๋ฉฐ null ๊ฐ๋ ๋ฐ์๋ ์ํ |
3. ์ํ ๋ฆฌํฌ์งํ ๋ฆฌ์ save() ๋ฉ์๋ ๋ถ์
JPA๋ฅผ ์ฌ์ฉํ ๋ ์๋ก์ด ์ํฐํฐ ์ ์ฅ๊ณผ ์ค์์ ์ํฐํฐ ์์ (๋ณํฉ)์ ํจ๊ป ์ฒ๋ฆฌํ๊ธฐ ์ํด ์๋์ ๊ฐ์ ๋ฉ์๋๋ฅผ ์ฌ์ฉํฉ๋๋ค.
@Repository
public class ItemRepository {
@PersistenceContext
private EntityManager em;
public void save(Item item) {
if (item.getId() == null) {
em.persist(item); // ์ ๊ท ์ํฐํฐ ์ ์ฅ
} else {
em.merge(item); // ๊ธฐ์กด ์ํฐํฐ ์์
}
}
}
save() ๋ฉ์๋์ ๋์ ๋ฐฉ์
- ์๋ณ์(ID)๊ฐ ์์ผ๋ฉด persist() ๋ฅผ ์คํํ์ฌ ์๋ก์ด ์ํฐํฐ๋ฅผ ์ ์ฅ
- ์๋ณ์(ID)๊ฐ ์์ผ๋ฉด merge() ๋ฅผ ์คํํ์ฌ ์ค์์ ์ํ์ ์ํฐํฐ๋ฅผ ๋ณํฉ
์ฃผ์ํ ์
- ๋ณํฉ์ ์ฌ์ฉํ๋ฉด ๋ชจ๋ ํ๋๊ฐ ๋ณ๊ฒฝ๋๋ฏ๋ก, ๋ณ๊ฒฝ ํผ์์ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ์ ์งํด์ผ ํจ
- ์ค๋ฌด์์๋ ํน์ ํ๋๋ง ์ ๋ฐ์ดํธํ๋ ๋ฐฉ์์ด ๋ ์์ ํจ → ๋ณ๊ฒฝ ๊ฐ์ง๋ฅผ ๊ถ์ฅ
4. ๊ฐ์ฅ ์ข์ ์ํฐํฐ ์์ ๋ฐฉ๋ฒ: ๋ณ๊ฒฝ ๊ฐ์ง ์ฌ์ฉ
์ค๋ฌด์์๋ ๋ณํฉ๋ณด๋ค ๋ณ๊ฒฝ ๊ฐ์ง(Dirty Checking) ๋ฐฉ์์ ์ฌ์ฉํ๋ ๊ฒ์ด ๋ ์์ ํ๊ณ ์ ์ฐํฉ๋๋ค.
์ฌ๋ฐ๋ฅธ ์์ ๋ฐฉ์
- ์ปจํธ๋กค๋ฌ์์ ์ง์ ์ํฐํฐ๋ฅผ ์์ฑํ์ง ์์
- ์๋น์ค ๊ณ์ธต์์ ์๋ณ์(ID)์ ๋ณ๊ฒฝํ ๋ฐ์ดํฐ๋ง ์ ๋ฌ (DTO ํ์ฉ ๊ฐ๋ฅ)
- ํธ๋์ญ์ ์ด ์๋ ์๋น์ค ๊ณ์ธต์์ ์์ ์ํ ์ํฐํฐ๋ฅผ ์กฐํ ํ ์ง์ ์์
์ปจํธ๋กค๋ฌ ์์
@Controller
@RequiredArgsConstructor
public class ItemController {
private final ItemService itemService;
@PostMapping("/items/{itemId}/edit")
public String updateItem(@PathVariable Long itemId, @ModelAttribute("form") BookForm form) {
itemService.updateItem(itemId, form.getName(), form.getPrice(), form.getStockQuantity());
return "redirect:/items";
}
}
์๋น์ค ๊ณ์ธต ์์
@Service
@RequiredArgsConstructor
public class ItemService {
private final ItemRepository itemRepository;
@Transactional
public void updateItem(Long id, String name, int price, int stockQuantity) {
Item item = itemRepository.findOne(id);
item.setName(name);
item.setPrice(price);
item.setStockQuantity(stockQuantity);
}
}
5. ๊ฒฐ๋ก
๋ณ๊ฒฝ ๊ฐ์ง vs ๋ณํฉ
- ๋ณ๊ฒฝ ๊ฐ์ง(Dirty Checking): ์ํ๋ ์์ฑ๋ง ๋ณ๊ฒฝ ๊ฐ๋ฅ, ๋ ์์ ํจ → ๊ถ์ฅ
- ๋ณํฉ(Merge): ๋ชจ๋ ํ๋ ๋ณ๊ฒฝ, null ๊ฐ ๋ฌธ์ ๋ฐ์ ๊ฐ๋ฅ → ์ ์คํ ์ฌ์ฉ
์ค๋ฌด์์์ Best Practice
- ์ปจํธ๋กค๋ฌ์์ ์ํฐํฐ๋ฅผ ์ง์ ์์ฑํ์ง ์์
- ์๋น์ค ๊ณ์ธต์์ ID์ ํ์ํ ๊ฐ๋ง ๋ช ํํ๊ฒ ์ ๋ฌ
- ํธ๋์ญ์ ๋ด์์ ์์ ์ํ ์ํฐํฐ๋ฅผ ์กฐํ ํ ์ง์ ๋ณ๊ฒฝ
- ์ต์ข ์ ์ผ๋ก ํธ๋์ญ์ ์ปค๋ฐ ์ ๋ณ๊ฒฝ ๊ฐ์ง ๊ธฐ๋ฅ์ ํ์ฉํ์ฌ ์ ๋ฐ์ดํธ ์ํ
์ด๋ฌํ ๋ฐฉ์์ผ๋ก JPA์ ์์์ฑ ์ปจํ ์คํธ๋ฅผ ํ์ฉํ๋ฉด ๋ ์์ ํ๊ณ ํจ์จ์ ์ธ ์ํฐํฐ ๊ด๋ฆฌ๊ฐ ๊ฐ๋ฅํฉ๋๋ค.
'๐ฟ Framework > Spring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
JPA๋? ๊ฐ๋ , ์์์ฑ ์ปจํ ์คํธ, JPQL๊น์ง ํ๋ฒ์ ์ ๋ฆฌ (1) | 2025.03.06 |
---|---|
Thymeleaf ํ ํ๋ฆฟ ์์ง (2) | 2024.10.20 |
[Spring]๊ฐ์ฒด ์งํฅ ์ค๊ณ์ ์คํ๋ง (0) | 2022.10.22 |
[Spring]ํ๋ก์ ํธ ํ๊ฒฝ์ค์ (1) | 2022.10.17 |