๐ ์๋ ๊ฐ ๋ฌด์ํ๋ JPA ๋ฉ์๋๋ค โ ์ด๊ฒ๋ง ์๋ฉด Spring Boot ์ ํ๋ฆฌ์ผ์ด์ 10๋ฐฐ ๋นจ๋ผ์ง๋ค!
์๋ ๊ฐ ๋ฌด์ํด์๋ ํต์ฌ JPA ๋ฉ์๋์ ์ด๋ ธํ ์ด์ ๋ค์ ๋ง์นจ๋ด ํ๊ตฌํด๋ณด๋, ๋๋ผ์ด ์ผ์ด ๋ฒ์ด์ก์ต๋๋ค. ์ ํ๋ฆฌ์ผ์ด์ ์ด 10๋ฐฐ ๋ ๋นจ๋ผ์ง๊ณ , ์ฟผ๋ฆฌ ์๋ ์ค์ด๋ค๊ณ , ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋๋ ๊ฐ์ํ์ผ๋ฉฐ, ์ฝ๋๋ ํจ์ฌ ๊น๋ํด์ก์ต๋๋ค.

๐ 1. existsById() โ findById() ๋์ ์ฌ์ฉํ๊ธฐ
๋จ์ํ ์กด์ฌ ์ฌ๋ถ๋ง ํ์ธํ๋ฉด ๋ ๋:
if (userRepository.existsById(id)) {
// ์ ์ฒด ์ํฐํฐ๋ฅผ ๋ก๋ํ ํ์ ์์
}
โ ์ ๋ ๋น ๋ฅธ๊ฐ?
- ๋ถํ์ํ ์ํฐํฐ ๋ก๋ฉ์ ํผํจ
- SQL ํฌ๊ธฐ ๊ฐ์
- ๋จ์ํ
SELECT COUNT(*)๋๋SELECT 1์ฟผ๋ฆฌ๋ง ์คํ
๐พ 2. saveAll() โ ์๋ฌต์ ๋ฐฐ์น ์ ์ฅ
์๋ ๊ฐ ์ด๋ ๊ฒ ์ ์ฅํ๋ค๋ฉด...
// โ ๋นํจ์จ์ ์ธ ๋ฐฉ์
for (User user : users) {
userRepository.save(user);
}
์ด์ ์ด๋ ๊ฒ ๋ฐ๊พธ์ธ์:
// โ
ํจ์จ์ ์ธ ๋ฐฉ์
userRepository.saveAll(users);
๐ก ํํธ
saveAll()์ ๋ด๋ถ์ ์ผ๋ก ๊ฐ ์ํฐํฐ์ ๋ํด save()๋ฅผ ํธ์ถํ์ง๋ง, hibernate.jdbc.batch_size๋ฅผ ์ค์ ํ๋ฉด persistence context๊ฐ ๋ฐฐ์น ์ฒ๋ฆฌ๋ฅผ ์ต์ ํํ ์ ์์ต๋๋ค.
โ๏ธ 3. saveAndFlush() โ ์ฆ์ ์์ํ
๐ง ๋ฌธ์ ์ํฉ
๋ ์ฝ๋๋ฅผ ์์ฑํ ํ ์ฆ์ ํด๋น ๋ฐ์ดํฐ๊ฐ DB์ ์์ด์ผ ํ๋ ๋ค๋ฅธ ์์ ์ ์ํํด์ผ ํ ๋ (๋ค์ดํฐ๋ธ ์ฟผ๋ฆฌ, ํธ๋ฆฌ๊ฑฐ, ๋ค๋ฅธ ์๋น์ค์์ DB ์กฐํ ๋ฑ)
// โ ๋ฌธ์ ๊ฐ ๋ ์ ์๋ ์ฝ๋
User newUser = userRepository.save(user);
auditRepository.save(new AuditLog("User created: " + newUser.getId()));
save()๋ ์์ง ์ค์ ๋ก INSERT๋ฅผ flushํ์ง ์์๊ธฐ ๋๋ฌธ์, audit ์๋น์ค๊ฐ ๋ฌผ๋ฆฌ์ ์ผ๋ก ์์ํ๋ user์ ์์กดํ๋ค๋ฉด ์คํจํ ์ ์์ต๋๋ค.
๐ก ํด๊ฒฐ์ฑ
โ saveAndFlush() ์ฌ์ฉ
// โ
์ฆ์ ์์ํ
User newUser = userRepository.saveAndFlush(user);
auditRepository.save(new AuditLog("User created: " + newUser.getId()));
โ ๋์ ๋ฐฉ์
saveAndFlush()๋ ๋ ๊ฐ์ง ์์
์ ์ํํฉ๋๋ค:
- ์ํฐํฐ๋ฅผ ์์ํ (
save()์ฒ๋ผ) - ๋ด๋ถ์ ์ผ๋ก
EntityManager.flush()๋ฅผ ์ฆ์ ํธ์ถ
์ ๋ ์ฝ๋๊ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฐ๋ก ๊ธฐ๋ก๋ฉ๋๋ค.
๐ชถ 4. getReferenceById() โ ๊ฒฝ๋ ์ํฐํฐ ๋ก๋
โ๏ธ ๋์ ์๋ฆฌ
getReferenceById()๋ EntityManager.getReference()์ Spring Data JPA ๋ํผ์
๋๋ค.
User userRef = userRepository.getReferenceById(userId);
order.setUser(userRef);
orderRepository.save(order);
โ ํต์ฌ ํฌ์ธํธ
- SQL ์ฟผ๋ฆฌ๊ฐ ์ฆ์ ์คํ๋์ง ์์
- JPA๊ฐ ์ํฐํฐ์ ๋ํ ์ง์ฐ ํ๋ก์(lazy proxy) ์์ฑ
- ID ์ธ์ ๋ค๋ฅธ ํ๋์ ์ ๊ทผํ ๋๋ง Hibernate๊ฐ DB ์กฐํ
๐ ์ ๋ ๋น ๋ฅธ๊ฐ?
๋ค๋ฅธ ์ํฐํฐ์์ ์ธ๋ ํค๋ฅผ ์ค์ ํ๊ธฐ ์ํด ์ํฐํฐ๋ฅผ ์ฐธ์กฐ๋ง ํ๋ฉด ๋๋ ๊ฒฝ์ฐ, ์ ์ฒด ๊ฐ์ฒด๋ฅผ DB์์ ๋ก๋ํ๋ ๊ฒ์ ์๊ฐ ๋ญ๋น์ ๋๋ค.
// โ
์ต์ ํ๋ ๋ฐฉ์
User userRef = userRepository.getReferenceById(userId);
order.setUser(userRef);
SELECT ์ฟผ๋ฆฌ ์์, ๋ฐ์ดํฐ ํ์นญ ์์, ๋จ์ง ์ฐธ์กฐ๋ง ์์ฑ๋ฉ๋๋ค.
๐งน 5. deleteById() โ ๊น๋ํ ์ญ์
์ด๋ ๊ฒ ์ญ์ ํ๋ค๋ฉด...
// โ ๋นํจ์จ์ ์ธ ๋ฐฉ์
User user = userRepository.findById(id).orElseThrow();
userRepository.delete(user);
์ด๊ฒ์ ๊ฐ์ฅ ํจ์จ์ ์ธ ๋ฐฉ๋ฒ์ด ์๋๋๋ค.
โ๏ธ ๋ ๋์ ๋ฐฉ๋ฒ
// โ
ํจ์จ์ ์ธ ๋ฐฉ์
userRepository.deleteById(userId);
โ ๊ฒฐ๊ณผ
- ์ํฐํฐ๋ฅผ ๋จผ์ ๊ฐ์ ธ์ค๋
SELECT์ฟผ๋ฆฌ ์์ - Spring Data JPA๊ฐ ์ฃผ์ด์ง ID์ ๋ํด ์ง์
DELETE FROM๋ฌธ ์คํ
๐ ์ ๋ ๋น ๋ฅธ๊ฐ?
delete(entity)๋ฅผ ํธ์ถํ๋ฉด Hibernate๋ ๋ณดํต ๋ ๋จ๊ณ๋ฅผ ์ํํฉ๋๋ค:
- ์ํฐํฐ๋ฅผ ๋ก๋ํ๊ธฐ ์ํ
SELECT์ฟผ๋ฆฌ ์คํ - ์ญ์ ๋ฅผ ์ํ
DELETE๋ฌธ ์คํ
deleteById()๋ ์ฒซ ๋ฒ์งธ ๋จ๊ณ๋ฅผ ๊ฑด๋๋๋๋ค!
๐ 6. flush() โ ๋๊ธฐํ ๋๊ตฌ
์ธ๋ป ๋ณด๋ฉด JPA์ flush()๊ฐ ์ ๋น๋ก์ธ ์ ์์ต๋๋ค. save()๋ฅผ ํธ์ถํ๋ฉด ์ํฐํฐ๊ฐ DB์ ๋ํ๋๊ณ ๋ชจ๋ ๊ฒ์ด "๊ทธ๋ฅ ์๋"ํ๋๊น์.
โ๏ธ flush()๊ฐ ์ค์ ๋ก ํ๋ ์ผ
save()๋ persist()๋ฅผ ํธ์ถํ ๋, ์ํฐํฐ๋ ๋ฉ๋ชจ๋ฆฌ์๋ง ์ ์ฅ๋๋ฉฐ ์ฆ์ DB์ ๊ธฐ๋ก๋์ง ์์ต๋๋ค.
flush()๋ Hibernate์๊ฒ ์ธ๋ฉ๋ชจ๋ฆฌ ์ํ๋ฅผ ์ค์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๊ฐ์ ๋ก ๋๊ธฐํํ๋๋ก ํฉ๋๋ค.
๐ก ์์ฝ
๐ก flush() = "๋๊ธฐ ์ค์ธ ๋ชจ๋ SQL ๋ณ๊ฒฝ ์ฌํญ(INSERT, UPDATE, DELETE)์ ์ง๊ธ ๋น์ฅ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ก ๋ณด๋ด๋ผ"
๐ฆ 7. findAll(Sort) / findAll(Pageable) โ ์ ๋ ฌ๊ณผ ํ์ด์ง๋ค์ด์
๋ชฉ์
์ ๋ ฌ๊ณผ ํ์ด์ง๋ค์ด์ ์ผ๋ก ์ํฐํฐ ์กฐํ
๐ช ์ ๊ฐ๋ ฅํ๊ฐ?
ํ์ํ ์ฌ๋ผ์ด์ค๋ง ๋ก๋ํ์ฌ ๋์ฉ๋ ๋ฐ์ดํฐ ์กฐํ๋ฅผ ์ต์ ํํฉ๋๋ค.
Page<User> users = userRepository.findAll(
PageRequest.of(0, 20, Sort.by("name"))
);
โ ์ฅ์
- ๋์ฉ๋ ์ฟผ๋ฆฌ๋ก ์ธํ ๋ฉ๋ชจ๋ฆฌ ๊ณผ๋ถํ ๋ฐฉ์ง
- ๋ด์ฅ๋ ํ์ด์ง๋ค์ด์ ์ด Spring Data์์ ์๋ ์ฒ๋ฆฌ
๐งฎ 8. count() โ ๋น ๋ฅธ ์นด์ดํธ
๋ชฉ์
๋ ์ฝ๋๋ฅผ ๊ฐ์ ธ์ค์ง ์๊ณ ๋น ๋ฅด๊ฒ ๊ฐ์๋ง ์ธ๊ธฐ
๐ช ์ ๊ฐ๋ ฅํ๊ฐ?
์ต์ ํ๋ SQL COUNT(*) ์คํ
long activeUsers = userRepository.countByStatus("ACTIVE");
โ ํ์ฉ์ฒ
๋์๋ณด๋, ์์ฝ ์ ๋ณด, ํ์ด์ง๋ค์ด์ ์ด ๊ฐ์์ ์ด์์
๐งฉ 9. JPA ํ์ ์ฟผ๋ฆฌ ๋ฉ์๋ โ ๋ณตํฉ ํค ๊ฒ์
Spring Data JPA์ ํ์ ์ฟผ๋ฆฌ ๋ฉ์๋๊ฐ ๋น์ ๋ฐํฉ๋๋ค.
โ๏ธ ๋์ ์๋ฆฌ
Spring Data JPA๋ ๋ฉ์๋ ์ด๋ฆ ์์ฒด๋ฅผ ๊ธฐ๋ฐ์ผ๋ก SQL ์ฟผ๋ฆฌ๋ฅผ ์๋ ์์ฑํ๋ ๋ฆฌํฌ์งํ ๋ฆฌ ๋ฉ์๋๋ฅผ ์ ์ํ ์ ์์ต๋๋ค.
์๋ @Query ์์, JPQL ์์, ๋ณด์ผ๋ฌํ๋ ์ดํธ ์์!
Optional<Client> findByClientIdAndCustomerNoAndCountryCode(
String clientId,
String customerNo,
String countryCode
);
Spring Data๊ฐ ์ด๊ฒ์ ํด์ํ์ฌ ๋ค์๊ณผ ๊ฐ์ ์ฟผ๋ฆฌ๋ฅผ ์๋ ์์ฑํฉ๋๋ค:
SELECT * FROM client
WHERE client_id = ?
AND customer_no = ?
AND country_code = ?;
โ ์ฅ์
- JPQL์ด๋ ๋ค์ดํฐ๋ธ SQL ํ์ ์์
- ๋ณด์ผ๋ฌํ๋ ์ดํธ ์ฝ๋ ์์
- ๋์ ๊ฐ๋ ์ฑ๊ณผ ํ์ ์์ ์ฑ
โก ๋ง์ง๋ง ํ
๐ JPA๋ฅผ ๋ธ๋๋ฐ์ค๋ก ์ทจ๊ธํ์ง ๋ง์ธ์. ์ ๊ตํ๊ฒ ํ๋๋ ์์ง์ฒ๋ผ ๋ค๋ฃจ์ธ์. ๊ทธ๋ฆฌ๊ณ ๋น์ ์ ์ธ์ ๊ฐ์ํ๊ณ , ์ธ์ ๊ธฐ์ด๋ฅผ ๋ฐ๊พธ๊ณ , ์ธ์ ๊ด์ฑ ์ฃผํํ ์ง ๊ฒฐ์ ํ๋ ๋๋ผ์ด๋ฒ์ ๋๋ค.
์ด ๋ฆฌ๋ฌ์ ์ตํ๋ฉด, JPA๋ Spring Boot ํดํท์์ ๊ฐ์ฅ ๊ฐ๋ ฅํ ๋๊ตฌ ์ค ํ๋๊ฐ ๋ฉ๋๋ค. ๐ช๐
๐ ๋ฉ์๋ ์์ฝ ํ
| ๋ฉ์๋ | ์ฉ๋ | ์ฑ๋ฅ ์ด์ |
|---|---|---|
existsById() | ์กด์ฌ ์ฌ๋ถ ํ์ธ | ์ํฐํฐ ๋ก๋ฉ ๋ถํ์ |
saveAll() | ๋ฐฐ์น ์ ์ฅ | ๋ฐฐ์น ์ต์ ํ ๊ฐ๋ฅ |
saveAndFlush() | ์ฆ์ ์์ํ | DB ์ฆ์ ๋ฐ์ |
getReferenceById() | ์ฐธ์กฐ๋ง ํ์ํ ๋ | SELECT ์ฟผ๋ฆฌ ์์ |
deleteById() | ID๋ก ์ญ์ | SELECT ์์ด ์ง์ DELETE |
flush() | ๊ฐ์ ๋๊ธฐํ | ์ฆ์ DB ๋ฐ์ |
findAll(Pageable) | ํ์ด์ง๋ค์ด์ | ํ์ํ ๋ฐ์ดํฐ๋ง ๋ก๋ |
count() | ๊ฐ์ ์กฐํ | ์ต์ ํ๋ COUNT ์ฟผ๋ฆฌ |
| ํ์ ์ฟผ๋ฆฌ | ์กฐ๊ฑด๋ถ ๊ฒ์ | ์๋ ์ฟผ๋ฆฌ ์์ฑ |
๐ ์ถ์ฒ
- ์๋ฌธ: I Ignored These JPA Methods for Years โ Now Spring Boot Application 10ร Faster
- ์ ์: Pramod Kumar
- ๊ฒ์์ผ: 2025๋ 11์ 8์ผ
- ์ถ์ฒ ํ๋ซํผ: FAUN.dev() ๐พ (Medium)



