Transactional
μ€νλ§μ PlatformTransactionManager
μΈν°νμ΄μ€λ₯Ό ν΅ν΄ νΈλμμ
μ μΆμννκ³ μ μΈμ νΈλμμ
μ μ§μνμ¬ νΈλμμ
μ νΈλ¦¬νκ² μ¬μ©ν μ μλλ‘ μ§μνλ€.
μ€νλ§ μ»¨ν μ΄λλ
@Transactional
μ λ Έν μ΄μ μ΄ μ μ©λ λΉμ μ°ΎμΌλ©΄, ν΄λΉ λΉμ μ€μ κ°μ²΄ λμ νΈλμμ λ‘μ§μ λ΄μ νλ‘μ κ°μ²΄λ₯Ό μμ±νμ¬ μ»¨ν μ΄λμ λ±λ‘λ€λ₯Έ λΉμμ μμ‘΄μ±μ μ£Όμ λ°μ λ, μ€νλ§ μ»¨ν μ΄λλ μ€μ κ°μ²΄ λμ νλ‘μ κ°μ²΄λ₯Ό μ£Όμ
ν΄λΌμ΄μΈνΈμ μμ²μ μ£Όμ λ°μ νλ‘μ κ°μ²΄λ₯Ό ν΅ν΄ μ λ¬λλ©°, νλ‘μλ νΈλμμ μ²λ¦¬ ν μ€μ κ°μ²΄μ λ©μλλ₯Ό νΈμΆ
νΈλμμ
λμ λ°©μκ³Ό λκΈ°ν
@Transactional
μ΄ μ μ©λ λ©μλκ° νΈμΆλ λμ νλ¦μ λ€μκ³Ό κ°λ€.
ν΄λΌμ΄μΈνΈμ μμ²μ νλ‘μ κ°μ²΄κ° λ¨Όμ λ°μ
νλ‘μλ νΈλμμ μ΄ νμνμ§ νμΈνκ³ , νμνλ€λ©΄
PlatformTransactionManager
λ₯Ό ν΅ν΄ νΈλμμ μ μμνλ‘μλ νΈλμμ λκΈ°ν λ§€λμ (
TransactionSynchronizationManager
)μ νμ¬ νΈλμμ μ 보λ₯Ό 보κ΄νλ‘μκ° μ€μ κ°μ²΄μ λ©μλλ₯Ό νΈμΆ
μ€μ κ°μ²΄μ λΉμ¦λμ€ λ‘μ§ μ€ν
λ‘μ§ μνμ΄ λλλ©΄ νλ‘μλ‘ μ μ΄κ° λμμ΄
μμΈ λ°μ μ¬λΆμ λ°λΌ νλ‘μλ
PlatformTransactionManager
μκ² νΈλμμ μ»€λ° λλ λ‘€λ°±μ μμ²νΈλμμ μ΄ μ’ λ£λκ³ , νΈλμμ λκΈ°ν λ§€λμ μ 보κ΄λ νΈλμμ μ λ³΄κ° μ 리
νΈλμμ
μ»€λ° κ³Όμ
νΈλμμ μ»€λ° κ³Όμ μ λ€μκ³Ό κ°μ λ¨κ³λ‘ μ΄λ£¨μ΄μ§λ€.
@Transactional
λ©μλκ° νΈμΆλλ©΄, μ€νλ§μ AOPλ₯Ό ν΅ν΄ νΈλμμ μ²λ¦¬ μμν΄λΉ νλ‘μλ μ€μ λΉμ¦λμ€ λ‘μ§ μ€ν μ νλ‘ νΈλμμ κ΄λ ¨ λΆκ° κΈ°λ₯μ μννλ
TransactionInterceptor
μ μ μ΄λ₯Ό μμTransactionInterceptorλ
PlatformTransactionManager
μ ꡬν체λ₯Ό μ¬μ©νμ¬ νΈλμμ μ μμνκ³ , λΉμ¦λμ€ λ‘μ§μ΄ μ μμ μΌλ‘ μλ£λλ©΄ μ»€λ° μμ²μ€μ μ»€λ° κ³Όμ μ
PlatformTransactionManager
μ μΆμ ν΄λμ€μΈAbstractPlatformTransactionManager
μprocessCommit
λ©μλμμ λ¨κ³μ μΌλ‘ μ²λ¦¬
processCommit
λ©μλμμ 컀λ°μ ν΅μ¬ λ‘μ§μ΄ μνλλ©°, μ£Όμ λ¨κ³λ λ€μκ³Ό κ°λ€.
private void processCommit(DefaultTransactionStatus status) {
try {
boolean beforeCompletionInvoked = false;
try {
prepareForCommit(status); // 1. μ»€λ° μ€λΉ
triggerBeforeCommit(status); // 2. μ»€λ° μ μ½λ°±
triggerBeforeCompletion(status); // 3. μλ£ μ§μ μ½λ°±
beforeCompletionInvoked = true;
// ... μΈμ΄λΈν¬μΈνΈ/νΈλμμ
λΆκΈ° μ²λ¦¬ λ±
else if (status.isNewTransaction()) {
doCommit(status); // 4. DB νΈλμμ
μ»€λ° (μ΄ μμ μ DB νΈλμμ
μ’
λ£)
}
} catch (Exception ex) {
// μμΈ λ°μ μ λ‘€λ°± λ° μμΈ μ ν
throw ex;
}
try {
triggerAfterCommit(status); // 5. μ»€λ° μ΄ν μ½λ°±
} finally {
triggerAfterCompletion( // 6. μλ£ ν μ½λ°±
status, TransactionSynchronization.STATUS_COMMITTED
);
}
} finally {
cleanupAfterCompletion(status); // 7. νΈλμμ
컨ν
μ€νΈ μ 리 (리μμ€ μΈλ°μΈλ©)
}
}
prepareForCommit
: νλ¬μ λ± μ»€λ° μ§μ μ€λΉ μνtriggerBeforeCommit
: μ»€λ° μ μ½λ°± μ€νμμ§ DB νΈλμμ μ΄ μ΄μμλ μν
triggerBeforeCompletion
: μλ£ μ§μ μ½λ°± μ€νdoCommit
: μ€μ DB μ»€λ° μνμ΄ μμ μ DB νΈλμμ μ΄ μ’ λ£
triggerAfterCommit
: μ»€λ° μ΄ν μ½λ°± μ€νDB νΈλμμ μ μ΄λ―Έ μ’ λ£λμμΌλ, μ€νλ§ νΈλμμ 컨ν μ€νΈλ μμ§ μ΄μμλ μν
triggerAfterCompletion
: μλ£ ν μ½λ°± μ€νcleanupAfterCompletion
: μ€λ λ 컨ν μ€νΈ μ 리
νΈλμμ
μ°μ μμ
@Transactional
μ λ
Έν
μ΄μ
μ ν΄λμ€, μΈν°νμ΄μ€, λ©μλμ μ μ©ν μ μμΌλ©°, μ°μ μμλ λ ꡬ체μ μ΄κ³ μμΈν κ²μ΄ λμ μ°μ μμλ₯Ό κ°μ§λ κ²μ μμΉμΌλ‘ νλ€.
ν΄λμ€μ λ©μλ
ν΄λμ€
μΈν°νμ΄μ€μ λ©μλ
μΈν°νμ΄μ€
μκΈ° νΈμΆ(Self Invocation)
@Transactional
μ΄ μ μ© λμ λ νΈλμμ
μ΄ μ μ©μ νλ‘μ κ°μ²΄λ₯Ό ν΅ν΄ μνλλλ°, λ§μ½ νλ‘μ κ°μ²΄λ₯Ό κ±°μΉμ§ μκ³ λμ κ°μ²΄λ₯Ό μ§μ νΈμΆνκ² λλ©΄ νΈλμμ
μ΄ μ μ©λμ§ μλλ€.
보ν΅μ κ²½μ°λ νλ‘μ κ°μ²΄λ₯Ό κ±°μΉκΈ° λλ¬Έμ λ¬Έμ κ° λμ§ μμ§λ§, λμ κ°μ²΄ λ΄λΆμμ λ©μλ νΈμΆμ νκ² λλ©΄ νλ‘μλ₯Ό κ±°μΉμ§ μκ² λμ΄ μμ λ¬Έμ κ° λ°μν μ μλ€.
class Example {
public void external() {
// do something
internal(); // νλ‘μλ₯Ό κ±°μΉμ§ μκ³ λμ κ°μ²΄ λ΄λΆμμ λ©μλ νΈμΆνκΈ° λλ¬Έμ νΈλμμ
μ΄ μ μ©λμ§ μλλ€.
}
@Transactional
public void internal() {
// do something
}
}
ν΄λΌμ΄μΈνΈμμ external λ©μλλ₯Ό νΈμΆνμ λ λ€μκ³Ό κ°μ νλ‘μΈμ€κ° μ§νλλ€.
ν΄λΌμ΄μΈνΈμμ νλ‘μ νΈμΆ
νλ‘μμμ external λ©μλμ νΈλμμ μ΄ μ μ©λμ΄ μμ§ μκΈ° λλ¬Έμ νΈλμμ μμ΄ λ©μλ νΈμΆ
μ€μ external λ©μλ μ€ν
external λ©μλ λ΄λΆμμ internal λ©μλ νΈμΆ
μ€ν λ internal λ©μλλ μ€μ κ°μ²΄μμ μ€νλκΈ° λλ¬Έμ νΈλμμ μ΄ μ μ©λμ§ μλλ€.
μ΄λ₯Ό λ°©μ§νκΈ° μν΄ μ¬λ¬ ν΄κ²°λ°©μλ€μ΄ μ‘΄μ¬νμ§λ§ λ³΄ν΅ μ€λ¬΄μμλ λ³λ ν΄λμ€λ‘ λΆλ¦¬νμ¬ νΈμΆνλ κ²μ΄ κ°μ₯ μ μ ν λ°©λ²μ΄λ€.
μ΄κΈ°ν μμ
μ€νλ§ μ΄κΈ°ν μμ μλ νΈλμμ AOPκ° μ μ©λμ§ μμ μ μκΈ° λλ¬Έμ νΈλμμ μ΄ νμν λ‘μ§μ΄ νμν λ©μλ μ€ν μμ μ μ€νλ§ μ»¨ν μ΄λκ° μμ ν μμ±λκ³ λ λ€μ νΈμΆν μ μλλ‘ μ€μ νλ κ²μ΄ μ’λ€.
class Hello {
@PostConstruct
@Transactional
public void init1() {
boolean isActive = TransactionSynchronizationManager.isActualTransactionActive();
log.info("tx active={} ", isActive); // false
}
@EventListener(ApplicationReadyEvent.class)
@Transactional
public void init2() {
boolean isActive = TransactionSynchronizationManager.isActualTransactionActive();
log.info("tx active={} ", isActive); // true
}
}
νΈλμμ
μ΅μ
@Transactional
μ λ
Έν
μ΄μ
μ ν΅ν΄ νΈλμμ
μ μ μ©ν λ μλμ κ°μ΄ μ΅μ
μ μ€μ ν μ μμΌλ©°, μ§μ νμ§ μμ κ²½μ°μ κΈ°λ³Έκ°μ΄ μ μ©λλ€.
@Transactional(isolation = Isolation.DEFAULT, readOnly = false)
class Example {
}
μ λ Έν μ΄μ μ μ μ©ν μ μλ μ΅μ λ€μ μλμ κ°λ€.
1. rollbackFor / noRollbackFor
μμΈ λ°μμ μ€νλ νΈλμμ μ λ‘€λ°± μ μ± μΌλ‘ κΈ°λ³Έ μ μ± μ μλμ κ°λ€.
μΈμ²΄ν¬ μμΈ: λ‘€λ°±
μ²΄ν¬ μμΈ: λ‘€λ°±νμ§ μκ³ μ»€λ°
μ΄ μ΅μ μ μΆκ°λ‘ λ‘€λ°±ν μμΈλ₯Ό μ§μ νκ² λλ©΄, ν΄λΉ μμΈκ° λ°μνμ λ λ‘€λ°±νκ² λλ€.
@Transactional(rollbackFor = Exception.class)
class Example {
}
λ°λλ‘ noRollbackFor
μ΅μ
μ λ‘€λ°±νμ§ μμ μμΈλ₯Ό μ§μ ν μ μλ€.
2. isolation
νΈλμμ
격리 μμ€ μ§μ μΌλ‘ λ³΄ν΅ λ°μ΄ν°λ² μ΄μ€μμ μ€μ ν νΈλμμ
μμ€μ μ¬μ©νλ DEFAULT
λ₯Ό μ¬μ©νλ€.
3. timeout
νΈλμμ νμμμμ μ§μ νλ μ΅μ μΌλ‘ κΈ°λ³Έκ°μ -1λ‘ λ¬΄μ νμ΄λ€.
4. readOnly
false
: μ½κΈ° μ°κΈ°κ° λͺ¨λ κ°λ₯ν νΈλμμ true
: μ½κΈ° μ μ© νΈλμμ (λλΌμ΄λ²λ DBμ λ°λΌ μ½κΈ° μ μ© νΈλμμ μ μ§μνμ§ μμ μ μμ)
5. propagation
νΈλμμ
μ ν μ΅μ
μΌλ‘ κΈ°λ³Έκ°μ REQUIRED
λ‘, λλΆλΆ μ΄ μ΅μ
μ μ¬μ©νλ€.
REQUIRED
νλμ νΈλμμ μ¬μ©
μλ‘μ΄ νΈλμμ μμ±
κΈ°μ‘΄ νΈλμμ μ¬μ©
REQUIRES_NEW
νμ μλ‘μ΄ νΈλμμ μ¬μ©
μλ‘μ΄ νΈλμμ μμ±
μλ‘μ΄ νΈλμμ μμ±
SUPPORT
νΈλμμ μ§μ
νΈλμμ μμ΄ μ§ν
κΈ°μ‘΄ νΈλμμ μ¬μ©
NOT_SUPPORTED
νΈλμμ λ―Έμ§μ
νΈλμμ μμ΄ μ§ν
νΈλμμ μμ΄ μ§ν(κΈ°μ‘΄ νΈλμμ 보λ₯)
MANDATORY
νΈλμμ μ΄ λ°λμ μ‘΄μ¬ν΄μΌ ν¨
μμΈ λ°μ
κΈ°μ‘΄ νΈλμμ μ¬μ©
NEVER
νΈλμμ μ μ¬μ©νμ§ μμ
νΈλμμ μμ΄ μ§ν
μμΈ λ°μ
isolation , timeout , readOnly λ νΈλμμ μ΄ μ²μ μμλ λλ§ μ μ©λλ©°, νΈλμμ μ μ°Έμ¬νλ κ²½μ°μλ μ μ©λμ§ μλλ€.
νΈλμμ
μ ν νλ¦ - REQUIRED μ΅μ
νΈλμμ
μ ν μ΅μ
μ΄ REQUIRED
μΈ κ²½μ° μ΄λ―Έ νΈλμμ
μ΄ μ‘΄μ¬νλ©΄ ν΄λΉ νΈλμμ
μ μ¬μ©νκ³ μμΌλ©΄ μλ‘μ΄ νΈλμμ
μ μμ±νκ² λλ€.
νλμ 컀λ°μ΄λΌλ λ°μνλ©΄ μ 체 νΈλμμ
μ΄ μ»€λ°λκ³ , νλμ λ‘€λ°±μ΄λΌλ λ°μνλ©΄ μ 체 νΈλμμ
μ΄ λ‘€λ°±λλ©°, κ·Έ μ리μ μμλ μλμ κ°λ€.

λ΄λΆ νΈλμμ μ€ν¨λ‘ μΈλΆ νΈλμμ μ΄ λ‘€λ°±λλ μμ
// μΈλΆ νΈλμμ
@Service
public class BatchRegistrationService {
private final MemberService memberService;
public BatchRegistrationService(MemberService memberService) {
this.memberService = memberService;
}
@Transactional
public void registerMultipleMembers() {
for (long point = 0; point < 5; point++) {
try {
memberService.registerMember(point);
} catch (Exception e) {
System.out.println("μμΈ λ°μ: " + e.getMessage());
}
}
}
}
// λ΄λΆ νΈλμμ
@Service
public class MemberService {
private final MemberRepository memberRepository;
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
@Transactional
public void registerMember(long point) {
if (point == 2L) {
throw new RuntimeException("ν¬μΈνΈκ° 2μΈ νμμ λ±λ‘ν μ μμ΅λλ€.");
}
Member member = new Member(point);
memberRepository.save(member);
}
}
μΈλΆ νΈλμμ μμ μμΈλ₯Ό κ°μΈμ μΈλΆ νΈλμμ μμμ μμΈ λ°μμ λ°©μ§νμ§λ§, λ΄λΆ νΈλμμ μμ μμΈκ° λ°μνμ¬ λ‘€λ°± λ§νΉλκΈ° λλ¬Έμ μ 체 νΈλμμ μ΄ λ‘€λ°±λλ€.
μ°Έκ³ μλ£
Last updated
Was this helpful?