π @Transactional(readOnly = true) λΆμ΄λ μ΄μ
μ€λμ @Transaction
, νΉν readOnly = true μ΅μ
μ λνμ¬ κΉμ΄ νκ΅¬ν΄ λ³΄κ² λ€.
μ°λ¦¬λ @Transaction
μ΄λ
Έν
μ΄μ
μ ν΅ν΄(Spring AOPλ‘) νΈλ μ μ
λ²μλ₯Ό μ½κ² ꡬνν μ μλ€.
μ¬κΈ°μ μ‘°νλ§μ μν λ‘μ§μλ @Transactional(readOnly = true)
μ΅μ
μ μΆκ°νμ¬ μ±λ₯μ λμ¬μ£Όλ μ¬μ€μ λͺ¨λ μκ³ μμ κ²μ΄λ€. μ¬κΈ°μ μ΄λ ν λ‘μ§μ κ±°μ² μ±λ₯μμ μ΄μ μ μ»μ΄λ΄λμ§ νκ΅¬ν΄ λ³΄κ² λ€.
λ°μ΄ν°λ² μ΄μ€μ μνλ₯Ό λ³κ²½νκΈ°μν΄ μννλ μμ μ λ¨μ.
λ°μ΄ν°μ 무결μ±μ 보μ₯νλ κ².
무결μ±μ μμμ μ€λͺ νλλ‘ λ°μ΄ν°κ° μ ννκ³ μ ν¨ν μνκ³ ,
μ ν©μ±μ λ°μ΄ν°μ κ°μ΄ μλ‘ μΌμΉνλ μνλ₯Ό λ»νλ€.(λ°μ κ·νλ₯Ό ν΅ν΄ μ΄μνμμ΄ λ°μνλ©΄ μ ν©μ±μ΄ κΉ¨μ§λ€.)
μ ν©μ±μ μ§ν€μ§λ§ 무결μ±μ΄ κΉ¨μ§ μνμ μλ₯Ό λ€μλ©΄,
μ£Όλ¬Έν
μ΄λΈ
κ³Ό κ³ κ°ν
μ΄λΈ
μ idxκ°μ΄ λͺ¨λ -1 μ΄λΌλ©΄ μ ν©μ±μ μ§ν€κ³ μμ§λ§, λ°λμ 1μ΄μμ κ°μ κ°μ ΈμΌνλ€λ idxκ°μ κ·μΉμ μν΄ λ°μ΄ν° 무결μ±μ΄ νΌμλκ² λλ€.
@Transactional
μ κΈ°λ³Έ κ°λ
μ¬μ©μ λ€μκ³Ό κ°μ΄ μ¬μ©λλ€.
@Transactional
public void doBusinessLogic() {
...
}
@Transactional
μ μμΉμ νλ‘μ λ©μ»€λμ¦@Transactional
μ Spring AOPμ μΈν°νμ΄μ€ κΈ°λ° (JDK λμ νλ‘μ) λλ ν΄λμ€ κΈ°λ° (CGLIB) μΌλ‘ νλ‘μλ₯Ό μμ±νλ€.public class A {
@Transactional
public void methodA() {
methodB(); // νΈλμμ
μ μ© μλ¨!
}
@Transactional
public void methodB() { ... }
}
@Transactional(readOnly = true)
λ¨μ μ‘°ν μ μ© λ©μλμ μ μ©νμ¬ λ¦¬μμ€λ₯Ό μ μ½νλ€.
flush()
νμ¬ DBμ λ°μλκ² λλ€.μ΄μκ°μ΄ μ¬μ©μκ° μ§μ update쿼리 λ±μ μμ±νμ§ μμλ, μν°ν°μ λ³κ²½μ μ κ°μ§νμ¬ μλμΌλ‘ μμ /λ°μ ν΄μ£Όλ κ²μ΄ μμμ± μ»¨ν μ€νΈμ λ³κ²½κ°μ§ κΈ°λ²μ΄λ€.
μμ λ§νλ―, readOnly = true
μ΅μ
μ΄ μΌμ Έμλ€λ©΄, flushλ°μκ³Ό μλκ°μ§μ λμμ λ©μΆλ€.
μ¦, JPAμΈμ
μ νλ¬μ λͺ¨λλ₯Ό MANUALλ‘ λ³κ²½νμ¬ κ°μ λ‘ flushλ₯Ό νΈμΆνμ§ μλ ν, μν°ν° μμ λ΄μμ DBμ λ°μλμ§ μλλ€.
readOnly = true
μ΅μ
μ΄ μΌμ Έμλ€λ©΄, JPAλ ν΄λΉ νΈλ μ μ
μ΄ λ΄μ μ‘°ν 쿼리μ λν΄μ, λ³κ²½κ°μ§λ₯Ό μν μ΄κΈ°μν(SnapShot)μ μ μ₯νμ§ μμλ λκ³ , λΆνμν Dirty Checkingμ 건λ λ°κ² ν¨μΌλ‘ λ§€λͺ¨λ¦¬μ CPU리μμ€λ₯Ό μ κ°ν μ μλ€.// 1
@Transactional(readOnly = true)
public Member getMember(int memberId) {
..
return member;
}
// 2
@Transactional
public Loaner getLoaner(int memberId) {
Optional<Loaner> loaner = loanerRepository.findById(loanerId);
..
return loaner;
}
getMember(int memberId)
κ° μ½κΈ°μ μ© λ©μλλΌλκ²μ νμ
ν μ μλ€.βλκ° μ΄μμ DBMSλ₯Ό Master/Slave λΌλ μμ§μ ꡬ쑰λ₯Ό νμ©νμ¬ DBμ λΆνλ₯Ό λΆμ°μν€λ κΈ°μ β
Master DBμλ insert/update/delete μ κ°μ μμ μ μννλλ‘ νκ³ , select μμ μ Slave DBμμ
μμ νλλ‘ κ΅¬μ±νλ€.
λ§μ½, readOnly=ture μ΅μ μ ν΅ν΄, μ€λ μ· μ μ₯μ λ§κ³ μ‘°ν μλλ₯Ό μ¬λ¦¬λκ² λͺ©μ μ΄λΌλ©΄,
@Transactional μ΄λ Έν μ΄μ μ μμ ν μ§μ°λ©΄ λλκ² μλκ°?
// @Transactional(readOnly = true) -> μ£Όμμ²λ¦¬
public Member getMember(int idx) {
Member member = memberRepository.findByIdx(idx).get();
System.out.println(member.getName()); // Lazy Loading λ°μ
return member;
}
λ€μκ³Ό κ°μ΄ μ½λλ₯Ό ꡬμ±νλ€λ©΄?
κ·Έλ λ€λ©΄ λ€μκ³Ό κ°μ΄ osivμ΅μ μ falseλ‘ νκ³ μ¬μ€ννλ€λ©΄?
// application.properties
spring.jpa.open-in-view=false
LazyInitializationException
μ΄ λ°μνκ² λλ€.
μ΄λ μμμ± μ»¨ν μ€νΈκ° μ’ λ£λ μ΄ν(μ€μμ μν)μ ν΄λΉ μν°ν°μ μ κ·Όνλ € ν λ λ°μνλ μμΈμ΄λ€.
(DTOλ‘ λ³ννμ¬ μ§μ μν°ν°μ μ κ·Όν νμκ° μλλ‘ κ΄λ¦¬νλ μ΄μ μ΄κΈ°λ ν¨)
λ°λΌμ, OSIVμ΅μ μ΄ μΌμ Έμμ§ μλ€λ©΄, @Transactional μ΄λ Έν μ΄μ μ κ°μ λκ³ ,
μ‘°νμ© μΏΌλ¦¬λ§μ μν λ©μλμλ νμ readOnly=ture μ΅μ μ λΆμ¬μ£Όλκ²μ΄ λ°λμ§νλ€.