๐Ÿ” JPA์—์„œ์˜ Lock ์™„์ „ ์ •๋ณต!

๋„๋‘๋งจยท2025๋…„ 7์›” 1์ผ

๊ณต๋ถ€

๋ชฉ๋ก ๋ณด๊ธฐ
20/23

์šฐ๋ฅด์˜ Lock & JPA Lock ๊ฐ•์˜ ์ •๋ฆฌ


๐Ÿ’ก Lock์ด๋ž€?

์—ฌ๋Ÿฌ ์ปค๋„ฅ์…˜์ด ๋™์‹œ์— ๋™์ผํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•˜๋ ค๊ณ  ํ•  ๋•Œ, ๋ฐ์ดํ„ฐ์˜ ์ผ๊ด€์„ฑ์„ ์ง€ํ‚ค๊ธฐ ์œ„ํ•œ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ž…๋‹ˆ๋‹ค.

  • ๋ฐ์ดํ„ฐ๋ฅผ ์ž ๊ถˆ(lock) ๋‘๋ฉด,
  • ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์€ ์ ‘๊ทผ ๋ถˆ๊ฐ€
  • ์—ฐ์‚ฐ์ด ๋๋‚˜๊ณ  ์ž ๊ธˆ ํ•ด์ œ๋˜๋ฉด ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์ด ์ ‘๊ทผ ๊ฐ€๋Šฅ

โœ… ์ฆ‰, ์ž๋ฌผ์‡ ์ฒ˜๋Ÿผ ๋ฐ์ดํ„ฐ๋ฅผ ์ž ๊ทธ๊ณ  ํ‘ธ๋Š” ๊ณผ์ •์ด Lock!


๐Ÿ” Lock vs Transaction

๊ฐœ๋…์„ค๋ช…
Lock๋ฐ์ดํ„ฐ ์ผ๊ด€์„ฑ์„ ์œ„ํ•œ ๋™์‹œ์„ฑ ์ œ์–ด ์ˆ˜๋‹จ
Transaction์ž‘์—…์˜ ์›์ž์„ฑ ๋ณด์žฅ (all or nothing)
ํŠธ๋žœ์žญ์…˜ ๊ฒฉ๋ฆฌ ์ˆ˜์ค€ (Isolation Level)์—ฌ๋Ÿฌ ํŠธ๋žœ์žญ์…˜ ๊ฐ„ ์ƒํ˜ธ ๊ฐ„์„ญ์„ ์–ผ๋งˆ๋‚˜ ํ—ˆ์šฉํ• ์ง€์— ๋Œ€ํ•œ ์ „๋žต
๐Ÿ”‘Lock์€ ์ด ๊ฒฉ๋ฆฌ ์ˆ˜์ค€์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜

โœŒ๏ธ ๋‚™๊ด€์  Lock (Optimistic Lock)

โ€œ์ถฉ๋Œ์ด ์ž˜ ์•ˆ ๋‚  ๊ฑฐ์•ผโ€๋ผ๋Š” ๋‚™๊ด€์ ์ธ ๊ฐ€์ •

  • ๋ฒ„์ „ ๊ธฐ๋ฐ˜์œผ๋กœ ์ถฉ๋Œ ํ™•์ธ
  • ํŠธ๋žœ์žญ์…˜ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•œ ํ›„์— ์ฒ˜๋ฆฌ
  • Application ์ˆ˜์ค€ Lock์ด๋ผ๊ณ ๋„ ๋ถˆ๋ฆผ

โœ… JPA์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ

@Version
private Long version;

๐Ÿ’ก ํŠน์ง•

  • ์—…๋ฐ์ดํŠธ ์‹œ ๋ฒ„์ „ ๋ถˆ์ผ์น˜ โžก๏ธ ์˜ˆ์™ธ ๋ฐœ์ƒ
  • ์„ฑ๋Šฅ์— ์œ ๋ฆฌ (๋ฝ์„ ์žก์ง€ ์•Š์Œ)
  • ๋Œ€์‹  ์ถฉ๋Œ ์‹œ ๋กค๋ฐฑ ๋ฐ ์žฌ์‹œ๋„ ํ•„์š”

๐Ÿ˜ฌ ๋น„๊ด€์  Lock (Pessimistic Lock)

โ€œํ•ญ์ƒ ์ถฉ๋Œ์ด ๋‚  ๊ฑฐ์•ผโ€๋ผ๋Š” ๋น„๊ด€์ ์ธ ๊ฐ€์ •

  • ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๋Š” ์ˆœ๊ฐ„๋ถ€ํ„ฐ ์ž ๊ธˆ
  • DB ์ˆ˜์ค€ Lock
  • ๋Œ€ํ‘œ ์˜ˆ: SELECT ... FOR UPDATE

โœ… JPA์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ

@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("select c from Coupon c where c.id = :id")
Optional<Coupon> findByIdForUpdate(Long id);

๐Ÿ’ก ํŠน์ง•

  • ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์ด ์ ‘๊ทผํ•˜์ง€ ๋ชปํ•จ
  • ์ •ํ™•ํ•œ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ์„ฑ๋Šฅ ์ €ํ•˜ ๊ฐ€๋Šฅ

๐Ÿงช ์‹ค์ „ ์˜ˆ์ œ โ€“ ์ฟ ํฐ ๋ฐœ๊ธ‰ ์‹œ๋‚˜๋ฆฌ์˜ค

๐ŸŽฏ ๋ชฉํ‘œ

  • ์ฟ ํฐ ์ด 5๊ฐœ
  • ๋™์‹œ์— 20๋ช…์ด ๋ฐœ๊ธ‰ ์š”์ฒญ

๐Ÿ”“ Lock ๋ฏธ์ ์šฉ

  • 20๋ช… ๋ชจ๋‘ ๋ฐœ๊ธ‰ ์„ฑ๊ณต โŒ (๋™์‹œ์„ฑ ๋ฌธ์ œ)

โœ… ๋‚™๊ด€์  Lock ์‚ฌ์šฉ

  • @Version ํ•„๋“œ๋กœ ์ถฉ๋Œ ๊ฐ์ง€
  • ๋ฒ„์ „์ด ์ผ์น˜ํ•ด์•ผ ์—…๋ฐ์ดํŠธ ์„ฑ๊ณต
  • ์‹ค์ œ ๊ฒฐ๊ณผ: 3๊ฐœ ๋ฐœ๊ธ‰๋งŒ ์„ฑ๊ณต
    โ†’ ๋‚˜๋จธ์ง€๋Š” ๋ฒ„์ „ ์ถฉ๋Œ๋กœ ์‹คํŒจ

โœ… ๋น„๊ด€์  Lock ์‚ฌ์šฉ

  • @Lock(LockModeType.PESSIMISTIC_WRITE) ์‚ฌ์šฉ
  • ํŠธ๋žœ์žญ์…˜ ํ•˜๋‚˜๊ฐ€ ์ฒ˜๋ฆฌ ์ค‘์ด๋ฉด ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์€ ๋Œ€๊ธฐ
  • ์‹ค์ œ ๊ฒฐ๊ณผ: ์ •ํ™•ํžˆ 5๊ฐœ ๋ฐœ๊ธ‰

๐Ÿค” ์–ธ์ œ ์–ด๋–ค Lock์„ ์จ์•ผ ํ• ๊นŒ?

์กฐ๊ฑด์ถ”์ฒœ Lock ๋ฐฉ์‹
์ถฉ๋Œ ๊ฐ€๋Šฅ์„ฑ ๋‚ฎ์Œโœ… ๋‚™๊ด€์  Lock
์ถฉ๋Œ ๊ฐ€๋Šฅ์„ฑ ๋†’์Œ, ์ •ํ™•ํ•œ ์ฒ˜๋ฆฌ ํ•„์š”โœ… ๋น„๊ด€์  Lock
์žฌ์‹œ๋„ ๋กœ์ง์ด ๊ตฌํ˜„๋˜์–ด ์žˆ์Œ๋‚™๊ด€์  Lock ์‚ฌ์šฉํ•ด๋„ OK
์ฒ˜๋ฆฌ๋Ÿ‰๋ณด๋‹ค ์ •ํ•ฉ์„ฑ์ด ๋” ์ค‘์š”๋น„๊ด€์  Lock ๊ณ ๋ ค

๐Ÿ“ ๋งˆ๋ฌด๋ฆฌ ์ •๋ฆฌ

๊ตฌ๋ถ„๋‚™๊ด€์  Lock๋น„๊ด€์  Lock
์ถฉ๋Œ ๊ฐ€์ •์ž˜ ์•ˆ ๋‚œ๋‹ค์ž์ฃผ ๋‚œ๋‹ค
์‚ฌ์šฉ ์œ„์น˜์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ (๋ฒ„์ „ ๊ธฐ๋ฐ˜)DB (์ž ๊ธˆ ๊ธฐ๋ฐ˜)
์„ฑ๋Šฅ์šฐ์ˆ˜๋‚ฎ์Œ (ํŠธ๋žœ์žญ์…˜ ๋Œ€๊ธฐ)
์ฒ˜๋ฆฌ ์‹คํŒจ ์‹œ์˜ˆ์™ธ ๋ฐœ์ƒ, ์žฌ์‹œ๋„ ํ•„์š”ํŠธ๋žœ์žญ์…˜ ๋Œ€๊ธฐ

๐Ÿ“Œ ์ถ”์ฒœ: ์‹ค๋ฌด์—์„œ๋Š”?

  • ๊ธฐ๋ณธ์€ ๋‚™๊ด€์  Lock ์‚ฌ์šฉ
  • ์ค‘๋ณต ๋ฐœ๊ธ‰, ์žฌ๊ณ  ์ฐจ๊ฐ, ์ •์‚ฐ์ฒ˜๋Ÿผ ์ •ํ•ฉ์„ฑ์ด ์ค‘์š”ํ•œ ๋ถ€๋ถ„์—๋Š”
    โ†’ ๋น„๊ด€์  Lock์„ ์ ์šฉํ•˜๋Š” ๊ฒƒ๋„ ๊ณ ๋ คํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค!

0๊ฐœ์˜ ๋Œ“๊ธ€