๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Spring & SpringBoot

Spring @Transaction์— ๋Œ€ํ•ด์„œ ๊นŠ์ด์žˆ๊ฒŒ ์•Œ์•„๋ณด์ž

by ์ฐฝ๋”ฐ์˜ค 2025. 4. 15.
728x90

๐ŸŒ€ Spring ํŠธ๋žœ์žญ์…˜ ์ „ํŒŒ(Propagation), ์–ธ์ œ ์–ด๋–ค ๊ฑธ ์จ์•ผ ํ• ๊นŒ?

Spring์—์„œ @Transactional์„ ์‚ฌ์šฉํ•  ๋•Œ propagation ์†์„ฑ์„ ์ •ํ™•ํžˆ ์ดํ•ดํ•˜๋Š” ๊ฑด ์ •๋ง ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.
ํŠธ๋žœ์žญ์…˜์ด ์ด๋ฏธ ์‹œ์ž‘๋˜์–ด ์žˆ์„ ๋•Œ, ํ˜ธ์ถœ๋œ ๋ฉ”์„œ๋“œ๋Š” ๊ทธ ํŠธ๋žœ์žญ์…˜์— ์ฐธ์—ฌํ• ์ง€, ์ƒˆ๋กœ ์‹œ์ž‘ํ• ์ง€๋ฅผ ์ด ์†์„ฑ์ด ๊ฒฐ์ •ํ•˜์ฃ .

์ด ํฌ์ŠคํŠธ์—์„œ๋Š” Spring์˜ ์ „ํŒŒ ์˜ต์…˜๋“ค์„ ์ •๋ฆฌํ•˜๊ณ , ์‹ค์ œ ์ƒํ™ฉ์— ๋งž๋Š” ์„ ํƒ๋ฒ•๋„ ํ•จ๊ป˜ ์†Œ๊ฐœํ• ๊ฒŒ์š”.


โœ… propagation์ด๋ž€?

ํŠธ๋žœ์žญ์…˜์ด ์žˆ๋Š” ์ƒํƒœ์—์„œ, ํ˜ธ์ถœ๋˜๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋ฐ˜์‘ํ• ์ง€ ์„ค์ •ํ•˜๋Š” ๊ฒƒ

Spring์€ ์ด 7๊ฐ€์ง€ ์ „ํŒŒ ์˜ต์…˜์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค:

์˜ต์…˜๋ช… ์„ค๋ช…
REQUIRED ํŠธ๋žœ์žญ์…˜์ด ์žˆ์œผ๋ฉด ์ฐธ์—ฌ, ์—†์œผ๋ฉด ์ƒˆ๋กœ ์‹œ์ž‘ (๊ธฐ๋ณธ๊ฐ’)
REQUIRES_NEW ํ•ญ์ƒ ์ƒˆ๋กœ์šด ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘, ๊ธฐ์กด ํŠธ๋žœ์žญ์…˜์€ ์ผ์‹œ ์ค‘๋‹จ
NESTED ์ค‘์ฒฉ ํŠธ๋žœ์žญ์…˜ ์ƒ์„ฑ (savepoint ๊ธฐ๋ฐ˜)
SUPPORTS ์žˆ์œผ๋ฉด ์ฐธ์—ฌ, ์—†์œผ๋ฉด ํŠธ๋žœ์žญ์…˜ ์—†์ด ์‹คํ–‰
NOT_SUPPORTED ํŠธ๋žœ์žญ์…˜์ด ์žˆ์œผ๋ฉด ์ค‘๋‹จ, ํŠธ๋žœ์žญ์…˜ ์—†์ด ์‹คํ–‰
MANDATORY ๋ฐ˜๋“œ์‹œ ํŠธ๋žœ์žญ์…˜ ์•ˆ์—์„œ๋งŒ ์‹คํ–‰, ์—†์œผ๋ฉด ์˜ˆ์™ธ
NEVER ํŠธ๋žœ์žญ์…˜์ด ์žˆ์œผ๋ฉด ์˜ˆ์™ธ ๋ฐœ์ƒ, ์—†์–ด์•ผ๋งŒ ์‹คํ–‰

๐Ÿ’ก ์ „ํŒŒ ์˜ต์…˜๋ณ„ ์˜ˆ์ œ์™€ ์‚ฌ์šฉ ์‹œ์ 

1. REQUIRED - ๊ธฐ๋ณธ๊ฐ’

@Transactional(propagation = Propagation.REQUIRED)
public void serviceA() {
    serviceB(); // ๊ฐ™์€ ํŠธ๋žœ์žญ์…˜์— ์ฐธ์—ฌ
}
โœ… ์ผ๋ฐ˜์ ์ธ CRUD, ์„œ๋น„์Šค ๊ณ„์ธต ๋กœ์ง์— ๊ฐ€์žฅ ์ ํ•ฉ

2. REQUIRES_NEW

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void serviceB() {
    // ๊ธฐ์กด ํŠธ๋žœ์žญ์…˜ ์ค‘๋‹จ, ์ƒˆ ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘
}
โœ… ์˜ˆ: ๋กœ๊ทธ ์ €์žฅ, ์•Œ๋ฆผ ์ „์†ก ๋“ฑ ๋ฉ”์ธ ๋กœ์ง๊ณผ ๋ถ„๋ฆฌ๋œ ์ž‘์—… ์ฒ˜๋ฆฌ

3. NESTED

@Transactional(propagation = Propagation.NESTED)
public void serviceC() {
    // savepoint ๊ธฐ๋ฐ˜ ์ค‘์ฒฉ ํŠธ๋žœ์žญ์…˜
}
โœ… ์ผ๋ถ€ ์ž‘์—…๋งŒ ๋กค๋ฐฑํ•˜๊ณ  ๋‚˜๋จธ์ง€๋Š” ์œ ์ง€ํ•˜๊ณ  ์‹ถ์„ ๋•Œ โš  JDBC savepoint ์ง€์›์ด ํ•„์š”

4. SUPPORTS

@Transactional(propagation = Propagation.SUPPORTS)
public void readService() {
    // ํŠธ๋žœ์žญ์…˜ ์œ ๋ฌด์— ๋”ฐ๋ผ ์œ ์—ฐํ•˜๊ฒŒ ์‹คํ–‰
}
โœ… ์ฝ๊ธฐ ์ „์šฉ ์„œ๋น„์Šค์— ์ ํ•ฉ

5. NOT_SUPPORTED

@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void externalCall() {
    // ํŠธ๋žœ์žญ์…˜ ์—†์ด ์‹คํ–‰
}
โœ… ์™ธ๋ถ€ API ํ˜ธ์ถœ ๋“ฑ ํŠธ๋žœ์žญ์…˜์ด ์˜คํžˆ๋ ค ๋ฌธ์ œ ๋  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ

6. MANDATORY

@Transactional(propagation = Propagation.MANDATORY)
public void coreLogic() {
    // ํŠธ๋žœ์žญ์…˜ ์—†์œผ๋ฉด ์˜ˆ์™ธ ๋ฐœ์ƒ
}
โœ… ๋ฌด์กฐ๊ฑด ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ ์‹คํ–‰๋˜์–ด์•ผ ํ•˜๋Š” ํ•ต์‹ฌ ๋กœ์ง

7. NEVER

@Transactional(propagation = Propagation.NEVER)
public void noTransactionAllowed() {
    // ํŠธ๋žœ์žญ์…˜ ์žˆ์œผ๋ฉด ์˜ˆ์™ธ
}
โœ… ํŠธ๋žœ์žญ์…˜์ด ์ ˆ๋Œ€ ์กด์žฌํ•ด์„  ์•ˆ ๋˜๋Š” ์ž‘์—…

โš ๏ธ ์‚ฌ์šฉ ์‹œ ์ฃผ์˜์‚ฌํ•ญ

  • ๋‚ด๋ถ€ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์‹œ @Transactional์€ ๋™์ž‘ํ•˜์ง€ ์•Š์Œ (ํ”„๋ก์‹œ ๋ฐฉ์‹์ด๊ธฐ ๋•Œ๋ฌธ)
  • REQUIRES_NEW๋Š” ํŠธ๋žœ์žญ์…˜์„ ๋ถ„๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์˜ˆ๊ธฐ์น˜ ์•Š์€ ์ปค๋ฐ‹/๋กค๋ฐฑ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Œ

๐Ÿ“Œ ์–ธ์ œ ์–ด๋–ค ๊ฑธ ์จ์•ผ ํ• ๊นŒ?

์ƒํ™ฉ ์ถ”์ฒœ ์ „ํŒŒ ์ „๋žต
์ผ๋ฐ˜์ ์ธ ์„œ๋น„์Šค ๋กœ์ง REQUIRED
๋ณ„๋„ ์ฒ˜๋ฆฌํ•  ๋ถ€๊ฐ€ ๋กœ์ง (๋กœ๊ทธ, ์•Œ๋ฆผ) REQUIRES_NEW
๋ถ€๋ถ„ ๋กค๋ฐฑ์ด ํ•„์š”ํ•œ ์„œ๋ธŒ ๋กœ์ง NESTED
ํŠธ๋žœ์žญ์…˜์ด ํ•„์ˆ˜์ธ ํ•ต์‹ฌ ๋กœ์ง MANDATORY
ํŠธ๋žœ์žญ์…˜ ์—†์ด ์‹คํ–‰ํ•ด์•ผ ํ•  ์ž‘์—… NOT_SUPPORTED or NEVER

๐Ÿง  ๋งˆ๋ฌด๋ฆฌ

ํŠธ๋žœ์žญ์…˜ ์ „ํŒŒ ์ „๋žต์„ ์ž˜ ์ดํ•ดํ•˜๊ณ  ์ ์šฉํ•˜๋ฉด, ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์˜ ์•ˆ์ •์„ฑ๊ณผ ์œ ์—ฐ์„ฑ์ด ํ›จ์”ฌ ํ–ฅ์ƒ๋ฉ๋‹ˆ๋‹ค.
ํŠนํžˆ REQUIRES_NEW๋‚˜ NESTED ๊ฐ™์€ ์ „๋žต์€ ์ž˜๋งŒ ์“ฐ๋ฉด ์‹ค๋ฌด์—์„œ ํฐ ํž˜์ด ๋˜์–ด์ค˜์š”.

๋ณต์žกํ•œ ํŠธ๋žœ์žญ์…˜ ํ๋ฆ„์— ๋งž๋‹ฅ๋œจ๋ ธ์„ ๋•, ์–ด๋–ค ์ „ํŒŒ ์˜ต์…˜์ด ์ ์ ˆํ•œ์ง€ ๊ผญ ํ•œ ๋ฒˆ ๊ณ ๋ฏผํ•ด๋ณด์„ธ์š”!