1. ๊ฐœ์š”

์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๋‹ค์ˆ˜์˜ ์‚ฌ์šฉ์ž๊ฐ€ ๋™์‹œ์— ๋™์ผํ•œ ๋ฐ์ดํ„ฐ(์˜ˆ: ์ˆ˜๊ฐ•๊ถŒ ์ž”์—ฌ ํšŸ์ˆ˜, ์ƒํ’ˆ ์žฌ๊ณ , ์ขŒ์„ ์˜ˆ์•ฝ)๋ฅผ ์ˆ˜์ •ํ•˜๋ ค๊ณ  ํ•  ๋•Œ, ๊ฐฑ์‹  ์†์‹ค(Lost Update) ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ ˆ๋ฒจ์—์„œ ๊ฐ•๋ ฅํ•˜๊ฒŒ ์ œ์–ดํ•˜๋Š” ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜๊ฐ€ ๋ฐ”๋กœ **๋น„๊ด€์  ๋ฝ(Pessimistic Lock)**์ž…๋‹ˆ๋‹ค.


2. ๋น„๊ด€์  ๋ฝ(Pessimistic Lock)์ด๋ž€?

์ด๋ฆ„์—์„œ ์•Œ ์ˆ˜ ์žˆ๋“ฏ์ด, ๋น„๊ด€์  ๋ฝ์€ **โ€œํŠธ๋žœ์žญ์…˜ ๊ฐ„์— ๋ฐ˜๋“œ์‹œ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•  ๊ฒƒ์ด๋‹คโ€**๋ผ๊ณ  ๋น„๊ด€์ ์œผ๋กœ ๊ฐ€์ •ํ•˜๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๋Š” ์ˆœ๊ฐ„๋ถ€ํ„ฐ DB ์ž์ฒด์˜ ๋ฝ์„ ๊ฑธ์–ด๋ฒ„๋ฆฌ๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

RDBMS์˜ SELECT ... FOR UPDATE ์ฟผ๋ฆฌ๋ฅผ ํ™œ์šฉํ•˜์—ฌ **๋ฐฐํƒ€ ๋ฝ(Exclusive Lock, X-Lock)**์„ ํš๋“ํ•ฉ๋‹ˆ๋‹ค. ๋ฝ์ด ๊ฑธ๋ฆฐ ๋ ˆ์ฝ”๋“œ๋Š” ๋ฝ์„ ํš๋“ํ•œ ํŠธ๋žœ์žญ์…˜์ด ์ปค๋ฐ‹(Commit)๋˜๊ฑฐ๋‚˜ ๋กค๋ฐฑ(Rollback)๋  ๋•Œ๊นŒ์ง€ ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์ด ์ˆ˜์ •ํ•  ์ˆ˜ ์—†์œผ๋ฉฐ, ์‹ฌ์ง€์–ด ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์ด ํ•ด๋‹น ๋ ˆ์ฝ”๋“œ์— ๋Œ€ํ•ด ๋น„๊ด€์  ๋ฝ์„ ํš๋“ํ•˜๋ ค๊ณ  ํ•˜๋ฉด ๋ฝ์ด ํ’€๋ฆด ๋•Œ๊นŒ์ง€ **๋Œ€๊ธฐ(Blocking)**ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

2-1. ๋‚™๊ด€์  ๋ฝ(Optimistic Lock)๊ณผ์˜ ์ฐจ์ด

  • ๋‚™๊ด€์  ๋ฝ: โ€œ์ถฉ๋Œ์ด ๊ฑฐ์˜ ๋ฐœ์ƒํ•˜์ง€ ์•Š์„ ๊ฒƒโ€์ด๋ผ ๊ฐ€์ •ํ•˜๊ณ  ๋ฝ์„ ๊ฑธ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋Œ€์‹  @Version ์ปฌ๋Ÿผ ๋“ฑ์„ ๋‘์–ด ์ปค๋ฐ‹ ์‹œ์ ์— ๋ฒ„์ „์ด ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ์ถฉ๋Œ์ด ์žฆ์œผ๋ฉด ๋กค๋ฐฑ๊ณผ ์žฌ์‹œ๋„ ๋น„์šฉ์ด ์ปค์ง‘๋‹ˆ๋‹ค.
  • ๋น„๊ด€์  ๋ฝ: ์ถฉ๋Œ์ด ์žฆ์„ ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋  ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋ฌด์กฐ๊ฑด ๋ฝ์„ ๊ฑธ๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ์ดํ„ฐ ์ •ํ•ฉ์„ฑ์€ ์™„๋ฒฝํžˆ ๋ณด์žฅ๋˜๋‚˜ ๋Œ€๊ธฐ ์‹œ๊ฐ„์œผ๋กœ ์ธํ•ด ์„ฑ๋Šฅ ์ €ํ•˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

3. ๋™์ž‘ ๋ฐฉ์‹ ์‹œ๋‚˜๋ฆฌ์˜ค

์ฝ˜์„œํŠธ ํ‹ฐ์ผ“ ์˜ˆ๋งค๋‚˜ ์„ผํ„ฐ ์Šค์ผ€์ค„ ์˜ˆ์•ฝ์„ ์ƒ๊ฐํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ž”์—ฌ ์ขŒ์„์ด 1๊ฐœ ๋‚จ์•˜์„ ๋•Œ ์‚ฌ์šฉ์ž A์™€ B๊ฐ€ ๋™์‹œ์— ์˜ˆ์•ฝ์„ ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค.

sequenceDiagram
    participant TxA as ํŠธ๋žœ์žญ์…˜ A
    participant TxB as ํŠธ๋žœ์žญ์…˜ B
    participant DB as Database (์ž”์—ฌ: 1)

    TxA->>DB: SELECT FOR UPDATE (์ž”์—ฌ: 1 ์ฝ์Œ, ๋ฝ ํš๋“)
    TxB->>DB: SELECT FOR UPDATE (TxA๊ฐ€ ๋ฝ์„ ํ•ด์ œํ•  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ โณ)
    Note over TxA: ์ž”์—ฌ = ์ž”์—ฌ - 1 (0์œผ๋กœ ์—ฐ์‚ฐ)
    TxA->>DB: UPDATE ์ž”์—ฌ = 0
    TxA->>DB: COMMIT (๋ฝ ํ•ด์ œ)
    
    Note over TxB: ๋Œ€๊ธฐ ํ•ด์ œ ๋ฐ ์ตœ์‹  ์ƒํƒœ(์ž”์—ฌ: 0) ์ฝ์Œ
    TxB->>DB: ๋ฝ ํš๋“
    Note over TxB: ์ž”์—ฌ ์ขŒ์„์ด 0์ด๋ฏ€๋กœ ๋น„์ฆˆ๋‹ˆ์Šค ์˜ˆ์™ธ ๋ฐœ์ƒ (์˜ˆ์•ฝ ์‹คํŒจ)
    TxB->>DB: ROLLBACK

๋น„๊ด€์  ๋ฝ ๋•๋ถ„์— ๋™์‹œ์— ์ ‘๊ทผํ•˜๋”๋ผ๋„ ์ˆœ์ฐจ์ ์œผ๋กœ(์ง๋ ฌํ™”๋˜์–ด) ์ฒ˜๋ฆฌ๋˜๋ฏ€๋กœ, ์ดˆ๊ณผ ์˜ˆ์•ฝ์ด๋ผ๋Š” ์น˜๋ช…์ ์ธ ๋ฒ„๊ทธ๋ฅผ ์™„๋ฒฝํ•˜๊ฒŒ ์ฐจ๋‹จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


4. Spring Data JPA์—์„œ์˜ ํ™œ์šฉ

Spring Data JPA์—์„œ๋Š” @Lock ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ๋งค์šฐ ์‰ฝ๊ฒŒ ๋น„๊ด€์  ๋ฝ์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import jakarta.persistence.LockModeType;
import org.springframework.data.jpa.repository.Lock;
import org.springframework.data.jpa.repository.Query;
 
public interface TicketRepository extends JpaRepository<TicketEntity, Long> {
 
    @Lock(LockModeType.PESSIMISTIC_WRITE)
    @Query("SELECT t FROM TicketEntity t WHERE t.uuid = :uuid")
    Optional<TicketEntity> findByUuidWithPessimisticLock(@Param("uuid") String uuid);
}
  • PESSIMISTIC_WRITE: ๋ฐฐํƒ€ ๋ฝ(Exclusive Lock)์„ ๊ฒ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์—์„œ ์ฝ๊ธฐ/์“ฐ๊ธฐ ๋ชจ๋‘ ๋Œ€๊ธฐํ•ฉ๋‹ˆ๋‹ค. (์ผ๋ฐ˜์ ์œผ๋กœ ๋™์‹œ์„ฑ ์ œ์–ด์— ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉ๋จ)
  • PESSIMISTIC_READ: ๊ณต์œ  ๋ฝ(Shared Lock)์„ ๊ฒ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์—์„œ ์ฝ์„ ์ˆ˜๋Š” ์žˆ์ง€๋งŒ ์“ธ ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค. (DB ๋ฐฉ์–ธ์— ๋”ฐ๋ผ ๋™์ž‘์ด ์กฐ๊ธˆ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Œ)

์ฃผ์˜์‚ฌํ•ญ

๋น„๊ด€์  ๋ฝ์€ ๋ฐ์ดํ„ฐ๋ฅผ ํ™•์‹คํ•˜๊ฒŒ ๋ณดํ˜ธํ•˜์ง€๋งŒ, ๋‚จ์šฉํ•˜๋ฉด ๋ณ‘๋ชฉ ํ˜„์ƒ์ด ์ƒ๊ฒจ ์‹œ์Šคํ…œ ์ฒ˜๋ฆฌ๋Ÿ‰(Throughput)์ด ํฌ๊ฒŒ ๋–จ์–ด์ง€๊ณ  **๋ฐ๋“œ๋ฝ(Deadlock)**์˜ ์›์ธ์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋ฝ์„ ์žก๋Š” ํŠธ๋žœ์žญ์…˜์˜ ํฌ๊ธฐ๋ฅผ ์ตœ๋Œ€ํ•œ ์ž‘๊ฒŒ ์œ ์ง€ํ•˜๊ณ , ์—ฌ๋Ÿฌ ํ…Œ์ด๋ธ”์— ๋ฝ์„ ๊ฑธ์–ด์•ผ ํ•  ๋•Œ๋Š” ๋ฐ˜๋“œ์‹œ ์ผ๊ด€๋œ ๋ฝ ํš๋“ ์ˆœ์„œ๋ฅผ ์œ ์ง€ํ•˜์—ฌ ๋ฐ๋“œ๋ฝ์„ ์˜ˆ๋ฐฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.