Development
μ°κ΄κ΄κ³ λ§€ν, κΌ ν΄μΌν κΉμ?
2024-09-26

μλ¦Όμ μ 보λ΄λ³΄μ
μꡬμ¬ν
νμ¬ μ§νμ€μΈ νλ‘μ νΈμ κΈ°λ₯ μ€μλ νΉμ μ건μ λν΄ ν¬νλ₯Ό λ°λ κΈ°λ₯μ΄ μμ΅λλ€. ν¬νκ° μ’ λ£λλ μκ° κ·Έ κ²°κ³Όλ₯Ό λ΄μ μλ¦Όμ λͺ¨λ ν¬νμλ€μκ² λ³΄λ΄μΌνλ©°, μλ¦Ό μ 보λ DBμ μ μ₯λμ΄μΌ ν©λλ€. μλ¦Ό ν μ΄λΈμ΄ νμλ‘ νλ μ 보λ μλμ κ°μ΅λλ€.

μ΄ ν μ΄λΈμ μΆν μ κ·νλ₯Ό μννμ΅λλ€^^
λ¬Έμ μ
μΌλ°μ μΌλ‘ JPAλ₯Ό μ¬μ©νμ¬ DBμ μ 보λ₯Ό μ μ₯νλ λ°©λ²μ μν°ν° κ°μ²΄λ₯Ό λ§λ€κ³ μμν λ©μλλ₯Ό νΈμΆνλ κ²μ λλ€.
// EntityManager
Notification noti = new Notification();
em.persist(noti);
// JpaRepository
Notification noti = new Notification();
notificationRepository.save(noti);νμ§λ§ μ λ°©λ²μΌλ‘ μλ¦Όμ 보λ΄κΈ°μλ μ μ νμ§ μμ κ² κ°μ΅λλ€. μμ±λλ μλ¦Όμ κ°μλ κ³§ ν¬νλ₯Ό μνν λͺ¨λ μ¬μ©μμ μμ λμΌνλ―λ‘ λ무 λ§μ μν°ν° μΈμ€ν΄μ€κ° μμ±λμ΄μΌ νκΈ° λλ¬Έμ λλ€.
// ν¬νμλ€μκ² λ³΄λΌ μλ¦Ό μμ±
List<Notification> notis = createNotification(voters);
// μ μ₯
notificationRepository.saveAll(notis);μ μ½λμ κ²½μ° 2κ°μ§ λ¬Έμ μ μ΄ λ°μν©λλ€.
1. λΆνμνκ² λ§μ λ©λͺ¨λ¦¬ μ¬μ©
λ§μ½ νΉμ μ건μ λν΄ ν¬νν μ¬λμ΄ Nλͺ μ΄λΌλ©΄ Notification κ°μ²΄ Nκ°κ° μμ±λ©λλ€. μ΄λ μκ°μ μΌλ‘ λ§μ λ©λͺ¨λ¦¬λ₯Ό μ¬μ©ν©λλ€. μλΉμ€μ κ·λͺ¨κ° 컀μ§μ λ°λΌ νλμ μ건μ λν΄ ν¬νν μ¬λμ μλ λμ΄λ κ²μ΄λ―λ‘, μ΄λ¬ν μ½λλ μ€λ«λμ μ μ§λμ§ λͺ»ν κ²μ λλ€.
2. λ°μνλ 쿼리μ κ°μ
JpaRepositoryμ saveAll() λ©μλλ κ°κ°μ μν°ν° κ°μ λ§νΌμ μ½μ
쿼리λ₯Ό DBμ μ μ‘ν©λλ€. λ무 λ§μ μ½μ
쿼리λ μνμκ°λ λ§μ΄ λ€κ³ DBμ λΆνλ₯Ό μ£ΌκΈ° μ½μ΅λλ€.
saveAll νΈμΆ μ μ μν°ν° κ°μλ§νΌμ μΏΌλ¦¬κ° λ°μνλ?
μ¬μ€ saveAll() λ©μλκ° νμ Nκ°μ μ½μ
쿼리λ₯Ό λ°μμν€λ κ²μ μλλλ€. μ΄λ IDμ μμ± μ λ΅μ΄ IDENTITYμΌ λμ Hibernate μ°κΈ° μ§μ° μ μ±
κ³Ό κ²°λΆλμ΄ λνλλ κ²°κ³Όμ
λλ€.
Hibernateλ μν°ν°λ€μ μμ±, μμ , μμ μ κ°μ μμ λ€μ μμμ± μ»¨ν μ€νΈμ 1μ°¨ μΊμμμ κ΄λ¦¬νλ€κ°, νΈλμμ μ΄ μ’ λ£λλ μμ μ ν΄λΉ λ΄μ©λ€μ DBμ λ°μνλ 쿼리λ₯Ό μνν©λλ€. μ΄λ₯Ό ν΅νμ¬ λΆνμν 쿼리 λ°μμ μ΅μννλ©° λ€νΈμν¬ μ°κ²°μ μ€λ²ν€λλ₯Ό μ€μΌ μ μμ΅λλ€.
νμ§λ§ IDENTITY μ μ± μ μ¬μ©νλ©΄ μν°ν° μμ± κ³Όμ μμ ꡬ쑰μ μΈ λ¬Έμ κ° λ°μν©λλ€. μν°ν°μ μμ± μμ μ μννλ©΄ 1μ°¨ μΊμμ μν°ν° μΈμ€ν΄μ€κ° μ μ₯λμ΄μΌ νλλ°, μ΄ λ IDλ DBMSκ° μλ μ¦κ° μ μλ‘ κ΄λ¦¬νλ―λ‘ DBλ₯Ό κ±°μΉμ§ μμΌλ©΄ ID κ°μ μ μ μμ΄ μ¨μ ν μν°ν° κ°μ²΄λ₯Ό μ μ₯ν μ μκΈ° λλ¬Έμ λλ€. μ΄λ¬ν μ΄μ λ‘ Hibernateλ IDENTITY μ μ± μ μ¬μ©νλ κ²½μ° persistκ° μνλλ μμ μ μ½μ 쿼리λ₯Ό λ°μμμΌ μμ±λ μλ μ¦κ° μ μλ₯Ό μν°ν°μ ν λΉνλ λ°©λ²μ μ¬μ©ν©λλ€.
μ λ°©λ²μ JDBC APIκ° μ 곡νλ μ½μ μ μμ±λ ν€λ₯Ό κ°μ Έμ€λ λ°©λ²μΌλ‘ ꡬνλ©λλ€. μ΄ λ°©λ²μ λ¨μΌ μ½μ μμλ μ ν¨νλ λ²ν¬μ± μ½μ μμλ μμ±λ ν€λ₯Ό κ²μνλλ°μ μ μ½μ΄ λ§μ΅λλ€. λ°λΌμ saveAll() λ©μλλ IDENTITY μ μ± μ μ¬μ©νλ μν°ν°λ€μ κ΄λ¦¬ν λμ μμμ± μ»¨ν μ€νΈμ ꡬ쑰λ₯Ό μ μ§νκΈ° μνμ¬ κ°κ°μ μν°ν°λ€μ κ°λ³μ μΌλ‘ μ½μ νλλ‘ λ§λ€μ΄μ Έ μμ΅λλ€.
λ²ν¬μ± μ½μ μ λμ
μ λ¬Έμ λ₯Ό ν΄κ²°νκΈ° μν΄ λ€μμ λ μ½λ μ½μ
μ νλμ μΏΌλ¦¬λ‘ μ²λ¦¬ν μ μλλ‘ JdbcTemplateμ batchUpdate()λ₯Ό μ¬μ©νκΈ°λ‘ νμ΅λλ€. batchUpdateλ bulk insertingμ μνν©λλ€.
@Override
public void insertNotifications(String message, String uri, Set<Long> memberIds) {
List<Object[]> parameters = new ArrayList<>();
//μ¬λ¬λΆλ€μ PreparedStatementλ₯Ό μ¬μ©νμΈμ
String sql = INSERT_NOTIFICATIONS_SQL
.replace(":message", message)
.replace(":uri", uri);
for (Long memberId : memberIds) {
parameters.add(new Object[] {memberId});
}
jdbcTemplate.batchUpdate(sql, parameters);
}νμ§λ§ μ΄λ¬ν λ°©μμ λ λ€λ₯Έ λ¬Έμ λ₯Ό λ³μμ΅λλ€. μλ¦Όμ μμ± μΏΌλ¦¬κ° νλλ‘ λκ°κΈ° λλ¬Έμ, λͺ¨μ’ μ μ΄μ λ‘ μΏΌλ¦¬ μνμ μ€ν¨νλ€λ©΄ μ 체 μλ¦Όμ λ±λ‘λμ§ μμ΅λλ€. 쿼리μ ννλ₯Ό λ³Ό λ λ¬Έμ μ μ¬μ§κ° μλ λΆλΆμ memberId μ κ΄λ ¨λ λΆλΆμ λλ€. νΉμλ λ©μλλ₯Ό νΈμΆνλ μΈ‘μμ μ‘΄μ¬νμ§ μλ memberIdλ₯Ό μ λ¬ν΄μ£Όκ±°λ, λ‘μ§μ΄ λλ μ¬μ΄μ ν΄λΉ IDλ₯Ό κ°μ§ μ¬μ©μκ° μμ λλ κ²½μ° μ°Έμ‘°λ¬΄κ²°μ±μ μν΄ μΏΌλ¦¬λ μ€ν¨ν κ²μ λλ€. 쿼리λ₯Ό κ°λ³μ μΌλ‘ λμ§λ€λ©΄ μ΄λ¬ν λ¬Έμ λ λ°μνμ§ μμΌλ―λ‘ λ²ν¬ μ½μ 쿼리λ μλ‘μ΄ λ¬Έμ λ₯Ό λ³μμ΅λλ€. μ΄λ¬ν μν©μ μλ¦Ό μμ€ν μ κ²°ν¨λ₯ μ λμ΄κ² λ©λλ€.
κ²°ν¨λ₯ μ€μ΄κΈ°
쿼리 μ€ν¨μ ν격μ μ€μ΄κΈ° μν΄, μμΈλ₯Ό μ‘μ 쿼리λ₯Ό λ€μ 보λ΄κ² λ§λ€μμ΅λλ€.
@Override
public void insertNotifications(String message, String uri, Set<Long> memberIds) {
...
try {
jdbcTemplate.batchUpdate(sql, parameters);
} catch (DataIntegrityViolationException e) {
//μλ¦Ό λ±λ‘ μ€ μ€λ₯ λ°μ, κ°λ³ μλ¦Ό λ±λ‘ μλ
for (Object[] parameter : parameters) {
try {
jdbcTemplate.update(sql, parameter);
} catch (DataIntegrityViolationException e2) {
//λ¬Έμ κ° μλ memberId
}
}
}
}μΏΌλ¦¬κ° μ€ν¨νμ λμ κ°κ°μ μλ¦Όμ κ°λ³μ μΌλ‘ λ±λ‘νλ λ°©μμΌλ‘ μ 체 μλ¦Όμ΄ λ±λ‘λμ§ μλ λ¬Έμ λ₯Ό ν΄κ²°νμμ΅λλ€. μ΄ κ²½μ° λ¬Έμ κ° μλ memberIdλ₯Ό μ μΈν λͺ¨λ μλ¦Όμ μ μ₯λ κ²μ λλ€.
μ΄ λ°©λ²μ μλ¦Ό μλΉμ€μ κ²°ν¨λ₯ μ μ€μ¬μ£Όμ§λ§ μ€ν¨νμ λμ Nκ°μ μΏΌλ¦¬κ° λ°μνλ©° μ±λ₯ μ νμ μμΈμ΄ λ μ μμ΅λλ€. μ΄λ₯Ό ν΄κ²°νκΈ° μν΄μ μ΄μ§ λΆν λ°©μμ μ±νν μ μμ΅λλ€. μ΄μ§ λΆν λ°©μμ λ²ν¬ μ½μ μ μ€ν¨νμ λ μ΄λ₯Ό λ λΆλΆμΌλ‘ λλμ΄ κ°κ°μ μμ΅μ μ½μ μ μννλ μ¬κ·μ μΈ ν΄λ²μ λλ€. μ΄μ§ λΆν λ°©μμΌλ‘ λ°°μΉμ ν¬κΈ°λ₯Ό μ λ°μΌλ‘ μ€μ¬κ°λ©° νΈμΆνλ©΄, νλμ λ μ½λμμ λ¬Έμ κ° λ°μνλ€λ κ°μ νμ Nκ°μ 쿼리λ₯Ό 1 + 2Γlogβ‘_2 Nο»Ώ κ°λ‘ μ€μΌ μ μμ΄ λ³΄μ λλ€.
μ°κ΄κ΄κ³ λ§€ν, κΌ ν΄μΌν κΉμ?
μ ν΄κ²°λ²μ λν μ‘°μΈμ λ£κΈ° μν΄ λ©ν λ§μ λ€κ³ κ°λλ°, μμ λ°μ μ루μ μ λ£κ² λμμ΅λλ€.
μ°κ΄κ΄κ³ λ§€ν, μ νμ ¨λμ?
public class Notification extends BaseTimeEntity {
...
@ManyToOne
@JoinColumn(name = "member_id")
private Member member;
...
}Notificationκ³Ό Memberλ λ€λμΌ κ΄κ³λ₯Ό κ°μ§κ³ μμΌλ―λ‘ λΉμ°νκ² DB λ 벨μμ FKλ‘ μ°κ²°λμ΄μμ΄μΌ νλ€κ³ μκ°νμ΅λλ€. κ·Έλ¦¬κ³ νλ‘μ νΈλ μμ§ κ°λ° λ¨κ³μ΄κ³ μν°ν°μ νλκ° κ³μ λ³ννκ³ μκΈ° λλ¬Έμ Hibernateκ° μ 곡νλ ddl μλ μμ± κΈ°λ₯μ μ¬μ©νκ³ μμμ΅λλ€. μ΄ κΈ°λ₯μ ν΅ν΄ νΈλ¦¬νκ² FKλ₯Ό μ€μ νλ €λ©΄ λ€λμΌ κ΄κ³λ₯Ό λ§€νν΄μ£Όμ΄μΌ νμ΅λλ€. μ΄ λΆλΆμ λν΄μ λ€μκ³Ό κ°μ μ§μ μ λ°μμ΅λλ€.
1. NotificationμΌλ‘λΆν° Member λ°μ΄ν°μ μ κ·Όν νμκ° μμ΄ λ³΄μ΄λλ° λ§€νμ΄ λμ΄μλ€.
νμ¬ μ ν리μΌμ΄μ μμ Notification ν μ΄λΈμ member_idλ μ€μ§ νΉμ νμμ μλ¦Όμ μ‘°ννκΈ° μν νν°λ§ μ©λλ‘ μ¬μ©λ©λλ€. Notification μ‘°νμ ν¨κ» Memberμ νλμ μ κ·Όν λ‘μ§μ΄ λ°μνμ§ μλλ€λ©΄, κ΅³μ΄ μ°κ΄κ΄κ³ λ§€νμ ν΄λμ μ΄μ λ μμ κ²μ λλ€.
λν μ΄λ¬ν ꡬ쑰λ MSAλ₯Ό λμ νκ² λ λμλ λ¬Έμ κ° λ μ μμ κ²μ λλ€. μλ¦Ό μμ€ν μ΄ κΈ°μ‘΄ μμ€ν κ³Ό λΆλ¦¬λμ΄ λ μμ μΈ μ ν리μΌμ΄μ μΌλ‘μ λμνκ² λ λ, Member νλλ₯Ό κ°κ³ μκ³ μ΄λ₯Ό μ¬μ©νκ² λλ©΄ μλ¦Ό μμ€ν μ΄ Member λλ©μΈμ μμ‘΄νκ² λμ΄ λΆλ¦¬νκΈ° μ΄λ €μΈ κ²μ λλ€.
2. FKλ‘ μ°κ΄κ΄κ³λ₯Ό μ£Όλ κ²λ λλ©μΈ κ° μμ‘΄μ±μ λλ¦°λ€.
μ ν리μΌμ΄μ λ 벨 λΏλ§ μλλΌ DB λ 벨μμλ FKμ μ€μ μ DB ν μ΄λΈκ° μμ‘΄μ±μ λ°μμμΌ λΆλ¦¬νκΈ° μ΄λ €μ΄ κ΅¬μ‘°κ° λ κ²μ λλ€. μν©μ λ°λΌμλ FKλ₯Ό μ¬μ©νμ§ μλ κ²λ λ°©λ²μ΄ λ μ μμ΅λλ€.
Notification - Member FK μ°κ²°μ νμ§ μλλ€λ©΄
FKλ ν μ΄λΈ κ°μ λ Όλ¦¬μ ꡬ쑰λ₯Ό 보μ₯ν μ μλ νλ₯ν λ°©λ²μ λλ€. νμ§λ§ FKλ₯Ό μ€μ νλ κ²μ μ μ½ μ‘°κ±΄μΌλ‘ μΈν μμ μ μ±λ₯ μ ν, μμ μ μ λ°μ΄νΈ μ λ°μνλ 볡μ‘μ±, ν μ΄λΈ κ° κ°ν μμ‘΄μ± λ°μ λ±μ λ¬Έμ λ₯Ό λ³μ΅λλ€. λ°λΌμ μ°Έμ‘° 무결μ±μ κΌ λ³΄μ₯ν΄μΌνλ κ²μ΄ μλλΌλ©΄, FKλ₯Ό μ¬μ©νμ§ μλ κ²λ κ³ λ €ν΄ λ³Ό μ μμ΅λλ€.
νμ¬ μ ν¬ μ ν리μΌμ΄μ μ κΈ°λ₯μ μκ°ν΄λ³Ό λ μλ¦Ό ν μ΄λΈμ μ°Έμ‘° 무결μ±μ΄ κΉ¨μ§λ κ²½μ°, μλ₯Ό λ€μ΄ member_idμ ν΄λΉνλ μ¬μ©μκ° μλ κ²½μ°λ μ¬μ€ ν° λ¬Έμ κ° λμ§ μμ΅λλ€. λͺ¨λ μλ¦Όμ μ‘°νλ member_idμ μν΄ νν°λ§ λμ΄μ μ‘°νλμ§λ§, μλ¦ΌμΌλ‘λΆν° μ¬μ©μ μΈ‘μ μ‘°ννλ κ²½μ°λ μκΈ° λλ¬Έμ λλ€. λ°λΌμ μ΄ μΌμ΄μ€λ FKμ μ°κ²°μ νμ§ μλ λ°©λ²μ μ’μ μμκ° λ μ μμ΄ λ³΄μ λλ€.
FKλ₯Ό μ κ±°νκ³ λλ€λ©΄ μμμ κ³ λ―Όνλ 쿼리 μ€ν¨μ λν μ²λ¦¬λ₯Ό ν νμμ± μμ²΄κ° μμ΄μ§λλ€. DBμ μ μ½ μ‘°κ±΄μ μ κ±°ν κ²μ΄ μ ν리μΌμ΄μ λ 벨μ 볡μ‘λλ₯Ό μ€μ΄λλ°μλ μν₯μ μ£Όμμ΅λλ€.
νμ§λ§ μ΄ κ²½μ° λ€λ₯Έ μ§μ μμ κ΄λ¦¬ ν¬μΈνΈκ° λ°μν©λλ€. κΈ°μ‘΄μλ μμ±λμ΄μΌ νλ μλ¦Όμ΄ μμ±λμ§ μλ κ²½μ°λ₯Ό κ΄λ¦¬ν΄μΌνμ§λ§, μ΄μ λ μμ±λμ§ μμμ΄μΌ νλ μλ¦Όμ΄ μμ±λλ κ²½μ°λ₯Ό κ΄λ¦¬ν΄μΌ ν©λλ€. μ΄λ¬ν λ μ½λλ€μ μ ν리μΌμ΄μ μ ν° μν₯μ μ£Όμ§λ μμ κ²μ΄μ§λ§, μ§μμ μΌλ‘ μμΈλ€λ©΄ λΆνμν 곡κ°μ λλΉνκ² λ©λλ€. λ°λΌμ μ£ΌκΈ°μ μΌλ‘ μ΄λ¬ν λ μ½λλ€μ μ§μμ£Όλ μν μ νλ λ°°μΉλ₯Ό μνμν€λ λ°©λ²λ κ³ μν΄λ³Ό νμκ° μμ κ²μ λλ€.