2023. 3. 12. 17:57γBackend/πΏ Spring
λͺ©μ°¨
0. Dirty Checking μ΄ λμνμ§ μμ λ΄ μ½λ
1. Dirty Checking μ μ΄λ€ 쑰건μμ μ€νλλκ°?
2. @Transactional μ μ΄λ€ μλ¦¬λ‘ Dirty Checking μ μ§ννλκ°?
3. κ·ΈλΌ μ΄λ»κ² μμ ν΄μΌνλ?
4. κ²°λ‘
Dirty Checking κ³Ό @Transactional μ μ리λ₯Ό μ μμλ λΆμ΄λΌλ©΄ μ΄ κΈμμ μ»μ΄κ°μλκ² λ§μ΄ μμ μ μμ΅λλ€. μ΄ κΈμ 무μ§μ±μΌλ‘ @Transactional μ μ¬μ©ν μ§λ λ μ λ°μ±νκ³ λ 곡λΆνκΈ° μν΄ μμ±νμ΅λλ€.
0. Dirty Checking μ΄ λμνμ§ μμ λ΄ μ½λ
λ무 λΆλλ½μ§λ§ μ²μμ μ΄λ κ² μ½λλ₯Ό μ§λκ³ μ Dirty Checking μ΄ λμ§ μλμ§ μμνλ€.
@Transactional μ΄λ Έν μ΄μ μ΄ μλ μνμμ User μ property λ₯Ό μμ νμΌλ λΉμ°ν μμ λμ΄μΌ νλκ±° μλκ°?
userλ λ°μ΄ν°λ² μ΄μ€μμ μ‘°νν μν°ν°λ₯Ό μΈλΆμμ μΈμλ‘ μ£Όμ νλ€.
@Component
@RequiredArgsConstructor
public class JwtTokenProvider {
private final UserRepository userRepository;
@Transactional
public void saveRefreshToken(User user, String newRefreshToken) {
...
user.setRefreshToken(newRefreshToken);
...
}
}
κ·ΈλΌ μ¬κΈ°μ λ΄κ° ν΄λ³Ό μ μλ μ§λ¬Έμ 2κ°μ§λ€.
1. Dirty Checking μ μ΄λ€ 쑰건μμ μ€νλλκ°?
2. @Transactional μ μ΄λ€ μλ¦¬λ‘ Dirty Checking μ μ§ννλκ°?
μ 2κ°μ§ λ¬Όμμ λ΅μ μ°¨λ‘λλ‘ νμ΄λ³΄κ² λ€.
1. Dirty Checking μ μ΄λ€ 쑰건μμ μ€νλλκ°?
μ°μ Dirty Checking μ΄ λ¬΄μμΈμ§ μμ보μ.
Dirty Checking λ μ΄ν리μΌμ΄μ λ΄λΆ μν°ν°μ λ³νλ₯Ό μΆμ νκΈ° μν΄ ORMμμ μ¬μ©λλ κ°λ μΌλ‘, λ³νλ₯Ό κ°μ§νκ³ νΈλμμ μ΄ commit λλ©΄ μμ μ¬νμ DBμ μλμΌλ‘ λ°μνλ κ²μ μλ―Ένλ€.
κ·ΈλΌ Dirty Checking μ μΈμ μ€νλ κΉ?
Dirty Checking μ νΈλμμ μ°κΈ° μ°μ° μ€ μμμ± μ»¨ν μ€νΈ(Persistent Context) κ° μν°ν°μ λ³κ²½μ κ°μ§ν λ μλμΌλ‘ μ€νλλ€.
JPAμμλ μν°ν°λ₯Ό μ‘°ννλ©΄ ν΄λΉ μν°ν°μ μ‘°ν μν κ·Έλλ‘ μ€λ μ·μ λ§λ€μ΄λλλ°, μ΄ μ€λ μ·μ μνμ λΉκ΅νμ¬ λ³κ²½μ¬νμ΄ μλ€λ©΄ μ€μΌ(Dirty)μ΄ κ°μ§(Checking) λλ€κ³ νλ¨νλ€. μ¦ μ΅μ΄ μ‘°νν μνμ λ€λ₯Ό λ Dirty Checking μ΄ κ°μ§λλ€.
μμμ± μ»¨ν μ€νΈ λΌλ λ¨μ΄κ° λ±μ₯νλ€. μμμ± μ»¨ν μ€νΈλ JPA λ°νμ νκ²½μΌλ‘ μν°ν°μ μλͺ μ£ΌκΈ° λ° DB μμμ±μ κ΄λ¦¬νλ μν μ 맑λλ€. μ½κ² λ§ν΄ μν°ν°μ μꡬ μ μ₯ νκ²½μ΄μ, μ ν리μΌμ΄μ κ³Ό DB μ¬μ΄μμ κ°μ²΄λ₯Ό 보κ΄νλ λ Όλ¦¬μ κ°λ μ΄λΌ ν μ μλ€. μμμ± μ»¨ν μ€νΈλΌλ μν°ν° μꡬ μ μ₯ νκ²½μ΄, μν°ν°μ λ³κ²½μ κ°μ§νλ€λ©΄ Dirty Checking μ΄ μ΄λ€μ§λ€κ³ λ³Ό μ μλ€.
μ 리νμλ©΄, μν°ν°κ° μμμ± μ»¨ν μ€νΈμ κ΄λ¦¬λ₯Ό λ°μ λ Dirty Checking μ μ€νλλ€.
κ·Έλ λ€λ©΄ μ΄ μμμ± μ»¨ν μ€νΈλΌλ κ²μ μ΄λ νμ΄λ°μ λ±μ₯νλ κ²μΌκΉ? μ΄ μ§λ¬Έμ λν λ΅μ @Transactional μ΄ κ°μ§κ³ μλ€.
2. @Transactional μ μ΄λ€ μλ¦¬λ‘ Dirty Checking μ μ§ννλκ°?
@Transactional μ νΈλμμ μ μμκ³Ό μ’ λ£ μ§μ μ ꡬλΆνλ νΈλμμ κ²½κ³λ₯Ό μ μΈν λ μ¬μ©λλ€.
@Transactionalμ΄ λΆμ λ©μλκ° νΈμΆλλ©΄ JPA λ μλ‘μ΄ νΈλμμ μ μμ±νμ¬ μμμ± μ»¨ν μ€νΈμ μ°κ²°μν¨λ€.
νΈλμμ μ μ’ λ£μ§μ μ ν΄λΉ νΈλμμ μ΄ commit λλ μμ μΌλ‘λ λ³Ό μ μλλ°, μ΄ μ»€λ° μμ μ μμμ± μ»¨ν μ€νΈλ νΈλμμ μ°κΈ° μμ μ ν΄λΉλλ Queryλ₯Ό μμ±νλ€. μ¦ ν΄λΉ νΈλμμ λ΄λΆμμ μμμ± μ»¨ν μ€νΈκ° μν°ν°μ λ³νλ₯Ό κ°μ§νλ©΄ μμ μ¬νμ λ§λ Query λ¬Έμ μμ±νλ€.
μ¬κΈ°μ μ€μν μ μ μμμ± μ»¨ν μ€νΈκ° λͺ¨λ μν°ν°μ λ³νλ₯Ό κ°μ§(Drity Checking)νμ§ μλλ€λ μ μ΄λ€.
μ₯? κ·ΈλΌ μ΄λ€ μν°ν°μ λ³νλ§ κ°μ§νλ κ²μΌκΉ? λ°λ‘ μμμ± μ»¨ν μ€νΈκ° κ΄λ¦¬νλ μν°ν°, μ¦ μμ μνμ μν°ν°λ§ Dirty Checking μ λμμ΄ λλ€. μν°ν°μκ² 4κ°μ§ μν(λΉμμ, μμ , μμ, μ€μμ)κ° μκ³ , μμ μνμ μν°ν°λ μ½κ² λ§ν΄ DBμ μ μ₯λμ΄ μλ λ°μ΄ν°λΌ ν μ μλ€.
λ€μ μ½λλ‘ λμμ보μ.
Dirty Checking μ λμμ΄ λκ³ μ νκΈΈ λ°λ¬λ μν°ν° User λ λΆλͺ DBλ‘λΆν° μ‘°νν κ°μ²΄λ€. νμ§λ§ μ΄λ₯Ό μμ μνμ μν°ν°λΌκ³ ν μ μλ€. μλ? ν΄λΉ μν°ν°λ @Transactional μΈλΆμμ μ£Όμ λ, μ¦ νμ¬ λ©μλμ μμμ± μ»¨ν μ€νΈμ κ΄λ ¨μλ μν°ν°μ΄κΈ° λλ¬Έμ΄λ€.
@Component
@RequiredArgsConstructor
public class JwtTokenProvider {
private final UserRepository userRepository;
@Transactional // ν΄λΉ νΈλμμ
κ²½κ³μ μ°κ²°λλ μμμ± μ»¨ν
μ€νΈμ 무κ΄ν user μν°ν°
public void saveRefreshToken(User user, String newRefreshToken) {
...
user.setRefreshToken(newRefreshToken);
...
}
}
- μ€μμ: Detach λ μν°ν°
- λΉμμ : DBμ λ°μλκΈ° μ μ²μ μμ±λ μν°ν°
μ λ μνμ μν°ν°λ Dirty Checking μ λμμ΄ μλλ€. κ·Έλ κΈ° λλ¬Έμ μ μ½λμμ λ©μλμ @Transactional μ λΆμ΄κ³ user μ κ°μ λ³κ²½ν΄λ DBμ λ°μλμ§ μλ κ²μ΄λ€.
μΈμλ‘ μ£Όμ λ°λ user μν°ν°λ 4κ°μ§ μν μ€ μ€μμ μνλ‘, DBμλ μ μ₯λΌ μμΌλ μμμ± μ»¨ν μ€νΈμμλ λΆλ¦¬λ μνλ€.
μ΄λ€ μμμ± μ»¨ν μ€νΈ? λ°λ‘ saveRefreshToken() μ νΈλμμ κ²½κ³μ μ°κ²°λ μμμ± μ»¨ν μ€νΈ!
μ 리νλ©΄ @Transactional μ Dirty Checking λμμ μμ μνμ μν°ν°μ νμ λλ©°, μ¬κΈ°μ μΈκΈν μμ μνμ μν°ν°λ ν΄λΉ νΈλμμ κ³Ό μ°κ²°λ μμμ± μ»¨ν μ€νΈκ° κ΄λ¦¬νλ μν°ν°λ₯Ό μλ―Ένλ€. μ΄λ₯Ό μ μΈν μν°ν°(user)μ λ³κ²½μλ ν΄λΉ μ¬νμ΄ μλ€!
3. κ·ΈλΌ μ΄λ»κ² μμ ν΄μΌνλ?
κ°λ¨νλ€. saveRefreshToken() μ νΈμΆνλ μμ κ³μΈ΅μμ User λ₯Ό μ‘°ννμ§ μκ³ , saveRefreshToken λ©μλ λ΄λΆμμ user μν°ν°λ₯Ό μ‘°ννλ©΄ λλ€. μ? μμ μνμ μν°ν°λ§ Dirty Checking μ΄ μ μ©λκΈ° λλ¬Έμ΄μ§. μμ λ μ½λλ μλμ κ°λ€.
@Component
@RequiredArgsConstructor
public class JwtTokenProvider {
private final UserRepository userRepository;
@Transactional
public void saveRefreshToken(String refreshToken, String something) {
...
User user = userRepository.findUserBySomething(something);
user.setRefreshToken(refreshToken);
...
}
}
4. κ²°λ‘
λμ΄μΌ 보면 λ΄κ° μλͺ»ν μ μ 2κ°μ§λ€.
0. μ½λλ₯Ό κ·Έμ§κ°μ΄
1. @Transactional μ리μ Dirty Checking 쑰건μ νμ νμ§ λͺ»ν μ
2. UserRepository μμ‘΄μ±μ μκ°νμ§ μκ³ μ½λλ₯Ό μ§ μ
μ€μ»· Dirty Chekcingκ³Ό @Transactiona μ κ΄ν κΈμ μΌμ§λ§ λλ²μ§Έ μμΈμ 'μμ‘΄μ±'μ΄λ€. UserRepository λ₯Ό μ΄λμ μ¬μ©ν μ§ μμ‘΄μ±μ μ κ³ λ €νλ μ½λλ₯Ό μ§°λ€λ©΄ μμ κ³μΈ΅μμ user λ₯Ό μΈμλ‘ λκΈ°μ§ μμμ κ²μ΄λ€. κ·Έλ¬λ€λ©΄ μμ μνμ μν°ν°μ @Transactional μ΄ μ μ©λμ΄ Dirty Checking λ μ λμνκ² μ§.
λλ κΈ°λ³Έμ΄ μ€μν¨μ λλΌλ μ¬κ±΄μ΄μλ€.