๐Ÿ’ป [Theory] JPA์˜ ๋‚™๊ด€์  ์ž ๊ธˆ(Optimistic Lock), ๋น„๊ด€์  ์ž ๊ธˆ(Pessimistic Lock)

๐Ÿ’ป [Theory] JPA์˜ ๋‚™๊ด€์  ์ž ๊ธˆ(Optimistic Lock), ๋น„๊ด€์  ์ž ๊ธˆ(Pessimistic Lock)

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•˜๋‹ค๋ณด๋ฉด ์—ฌ๋Ÿฌ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋“ค์„ ๋งŒ๋‚˜๊ณ  ๋™์‹œ์„ฑ ์ œ์–ด๋ฅผ ๋„์™€์ฃผ๋Š” ์—ฌ๋Ÿฌ ์‹œ์Šคํ…œ๋“ค(๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์‹œ์Šคํ…œ, JPA ์‹œ์Šคํ…œ ๋“ฑ) ์„ ๋ณด๊ฒŒ๋ฉ๋‹ˆ๋‹ค.
ํŠนํžˆ๋‚˜ ๋งŽ์€ ์‚ฌ์šฉ์ž๊ฐ€ ์žˆ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ผ ์ˆ˜๋ก ๋™์‹œ์„ฑ ๋ฌธ์ œ๊ฐ€ ๋” ์ค‘์š”ํ•˜๊ณ  ์ด๋ฅผ ์ œ์–ดํ•ด์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
๋™์‹œ์„ฑ ์ œ์–ด๋ฅผ ๋„์™€์ฃผ๋Š” ๋ฐฉ๋ฒ•๋“ค ์ค‘
์ด๋ฒˆ์—” JPA ์‹œ์Šคํ…œ์—์„œ์˜ ๋‚™๊ด€์  ์ž ๊ธˆ(Optimistic Lock), ๋น„๊ด€์  ์ž ๊ธˆ(Pessimistic Lock)์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.   

Locking์ด๋ž€ ?

  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•˜๋‹ค๋ณด๋ฉด ์—ฌ๋Ÿฌ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋“ค์„ ๋งŒ๋‚˜๊ฒŒ ๋จ.
    • ex) read skew, lost update ๋“ฑ๋“ฑ
  • ์—ฌ๋Ÿฌ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ ๊ทธ ์ค‘์—์„œ๋„ ๋ฐ์ดํ„ฐ์˜ ์ผ๊ด€์„ฑ์„ ์ง€ํ‚ค๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜์ด๋‹ค.

๋‚™๊ด€์  ์ž ๊ธˆ(Optimistic Lock)

  • ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ ๊ฐฑ์‹ ์‹œ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์„๊ฒƒ์ด๋ผ๊ณ  ๋‚™๊ด€์ ์œผ๋กœ ๋ณด๋Š” ๊ฒƒ.
  • ๋ฐ์ดํ„ฐ ๊ฐฑ์‹ ์‹œ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์„ ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ์šฐ์„ ์ ์œผ๋กœ ๋ฝ์„ ๊ฑธ์ง€ ์•Š๋Š”๋‹ค.
  • Version์„ ์‚ฌ์šฉํ•ด ๊ด€๋ฆฌํ•œ๋‹ค.
  • ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฝ
  • ์ถฉ๋Œ๋ฐฉ์ง€
  • ํŠธ๋žœ์žญ์…˜์„ ์ปค๋ฐ‹ํ•˜๊ธฐ ์ „๊นŒ์ง€๋Š” ํŠธ๋žœ์žญ์…˜์˜ ์ถฉ๋Œ์„ ์•Œ ์ˆ˜ ์—†๋‹ค.
  • ๊ฐ„๋‹จํžˆ @Version ์–ด๋…ธํ…Œ์ด์…˜์„ ์ด์šฉํ•ด ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ๋‹จ, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฃผ์˜์‚ฌํ•ญ์ด ์žˆ๋‹ค.
    • ๊ฐ ์—”ํ‹ฐํ‹ฐ ํด๋ž˜์Šค์—๋Š” ํ•˜๋‚˜์˜ ๋ฒ„์ „ ์†์„ฑ ๋งŒ ์žˆ์–ด์•ผํ•œ๋‹ค.
    • ์—ฌ๋Ÿฌ ํ…Œ์ด๋ธ”์— ๋งคํ•‘ ๋œ ์—”ํ‹ฐํ‹ฐ์˜ ๊ฒฝ์šฐ ๊ธฐ๋ณธ ํ…Œ์ด๋ธ”์— ๋ฐฐ์น˜๋˜์–ด์•ผํ•œ๋‹ค๋‹ค.
    • ๋ฒ„์ „์— ๋ช…์‹œํ•  ํƒ€์ž…์€ int, Integer, long, Long, short, Short, java.sql.Timestamp ์ค‘ ํ•˜๋‚˜ ์—ฌ์•ผํ•œ๋‹ค.

๋‚™๊ด€์  ์ž ๊ธˆ(Optimistic Lock) ์ฒ˜๋ฆฌ๋ฐฉ๋ฒ•

  • ๋‚™๊ด€์  ์ž ๊ธˆ์€ OptimisticLockException์„ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.
  • Persistence Provider๊ฐ€ Entity์—์„œ ๋‚™๊ด€์  ์ž ๊ธˆ ์ถฉ๋Œ์„ ๊ฐ์ง€ํ•˜๋ฉด OptimisticLockException์„ ๋ฐœ์ƒ์‹œํ‚ค๊ฒŒ ๋˜๊ณ  ํŠธ๋žœ์žญ์…˜์€ ๋กค๋ฐฑ์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.
  • ๊ถŒ์žฅ๋˜๋Š” ์˜ˆ์™ธ์ฒ˜๋ฆฌ ๋ฐฉ๋ฒ•์—์„œ๋Š” Entity๋ฅผ ๋‹ค์‹œ ๋กœ๋“œํ•˜๊ฑฐ๋‚˜ ์ƒˆ๋กœ๊ณ ์นจํ•˜์—ฌ ์—…๋ฐ์ดํŠธ๋ฅผ ์žฌ์‹œ๋„ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.
  • ์˜ˆ์™ธ์ฒ˜๋ฆฌ์‹œ์— ๋ฐœ์ƒ๋˜๋Š” Exception์—์„œ ์ถฉ๋Œ๋˜๋Š” Entity๋ฅผ ์ œ๊ณตํ•ด์ฃผ๊ณ  ์žˆ์–ด ์‰ฝ๊ฒŒ ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋„๋ก ๋˜์–ด์žˆ๋‹ค.

๋น„๊ด€์  ์ž ๊ธˆ(Pessimistic Lock)

  • ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ ๊ฐฑ์‹ ์‹œ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•  ๊ฒƒ์ด๋ผ๊ณ  ๋น„๊ด€์ ์œผ๋กœ ๋ณด๊ณ  ๋ฏธ๋ฆฌ ์ž ๊ธˆ์„ ๊ฑฐ๋Š” ๊ฒƒ
  • ๋ฐ์ดํ„ฐ ๊ฐฑ์‹ ์‹œ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์„ ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ์šฐ์„ ์ ์œผ๋กœ ๋ฝ์„ ๊ฑด๋‹ค(์กฐํšŒํ•  ๋•Œ ๋ถ€ํ„ฐ ๊ฑด๋‹ค).
  • ํŠธ๋žœ์žญ์…˜์˜ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๊ณ  ์šฐ์„  ๋ฝ์„ ๊ฑธ๊ณ  ๋ณด๋Š” ๋ฐฉ๋ฒ•
  • ํŠธ๋žœ์žญ์…˜์•ˆ์—์„œ ์„œ๋น„์Šค๋กœ์ง์ด ์ง„ํ–‰๋˜์–ด์•ผํ•จ.
  • DB ๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๋ฝ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉ( ex: ๊ณต์œ ๋ฝ- LOCK IN SHARE MODE, ๋ฒ ํƒ€๋ฝ-FOR UPDATE โ€ฆ)
  • ๋ฌด๊ฒฐ์„ฑ์˜ ์žฅ์ 
  • ๋ฐ๋“œ๋ฝ์˜ ์œ„ํ—˜์„ฑ
  • ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ • ์‹œ ์ฆ‰์‹œ ํŠธ๋žœ์žญ์…˜ ์ถฉ๋Œ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค

์•”์‹œ์  ์ž ๊ธˆ๊ณผ ๋ช…์‹œ์  ์ž ๊ธˆ

์•”์‹œ์  ์ž ๊ธˆ (Implicit Lock)

  • JPA์—์„œ๋Š” @Version์ด ๋ถ™์€ ํ•„๋“œ๊ฐ€ ์กด์žฌํ•˜๊ฑฐ๋‚˜ @OptimisticLocking ์–ด๋…ธํ…Œ์ด์…˜์ด ์„ค์ •๋˜์–ด ์žˆ์„ ๊ฒฝ์šฐ ์ž๋™์ ์œผ๋กœ ์ถฉ๋Œ๊ฐ์ง€๋ฅผ ์œ„ํ•œ ์ž ๊ธˆ์ด ์‹คํ–‰๋œ๋‹ค.
  • ์ด๋Š” Annotation๋งŒ ์„ค์ •ํ•ด์ฃผ๋ฉด ๋ณ„๋„์˜ ์ถ”๊ฐ€ ์„ค์ •์ด ์—†์–ด๋„ JPA์—์„œ ์ž๋™์ ์œผ๋กœ ํ–‰ํ•˜์—ฌ์ฃผ๋Š” ์ž ๊ธˆ์ด๋‹ค.
  • ์ถ”๊ฐ€๋กœ ์‚ญ์ œ ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ• ์‹œ์—๋Š” ์•”์‹œ์ ์œผ๋กœ ํ•ด๋‹น ๋กœ์šฐ์— ๋Œ€ํ•œ ํ–‰ ๋ฐฐํƒ€์ž ๊ธˆ(Row Exclusive Lock)์„ ์ œ๊ณตํ•˜์—ฌ์ค€๋‹ค.

๋ช…์‹œ์  ์ž ๊ธˆ (Explicit Lock)

  • ํ”„๋กœ๊ทธ๋žจ์„ ํ†ตํ•ด ์˜๋„์ ์œผ๋กœ ์ž ๊ธˆ์„ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด ๋ช…์‹œ์  ์ž ๊ธˆ์ด๋‹ค.
  • JPA์—์„œ EntityManager๋ฅผ ํ†ตํ•˜์—ฌ ์—”ํ„ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•  ๋•Œ LockMode๋ฅผ ์ง์ ‘ ์ง€์ •ํ•˜๊ฑฐ๋‚˜ select for update ์ฟผ๋ฆฌ๋ฅผ ํ†ตํ•ด์„œ ์ง์ ‘ ์ž ๊ธˆ์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

    Student student = entityManager.find(Student.class, id); entityManager.lock(student, LockModeType.OPTIMISTIC);

    Student resultStudent = entityManager.find(Student.class, studentId); entityManager.lock(resultStudent, LockModeType.PESSIMISTIC_WRITE);

์ •๋ฆฌ

  • ํŠธ๋žœ์žญ์…˜ ์ถฉ๋Œ์ด ์ž˜ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š” ํ™˜๊ฒฝ์—์„œ๋Š” ๋‚™๊ด€์ ์ธ ๋ฝ์ด ์ข‹๊ณ  ์ถฉ๋Œ์ด ์ž์ฃผ ๋ฐœ์ƒํ•˜๋Š” ํ™˜๊ฒฝ์—์„œ๋Š” ๋น„๊ด€์ ์ธ ๋ฝ์ด ์ข‹๋‹ค.
  • ๋‚™๊ด€์ ์ธ ๋ฝ(Optimistic Lock)์€ ์„ฑ๋Šฅ์—์„œ ์ด์ ์„ ๊ฐ–๋Š”๋‹ค.
  • ๋น„๊ด€์ ์ธ ๋ฝ(Pessimistic Lock)์€ ์šฐ์„ ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋‹จ์—์„œ ์ž ๊ธˆ์„ ๊ฑฐ๋ฏ€๋กœ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ๋ฌด๊ฒฐ์„ฑ, ์ •ํ•ฉ์„ฑ์— ์ด์ ์„ ๊ฐ–๋Š”๋‹ค.
  • ๊ฒฐ๊ตญ, locking ๊ธฐ๋ฒ•์— ์ •๋‹ต์ด ์žˆ๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋ฏ€๋กœ ๊ฐ ์ƒํ™ฉ์— ๋งž๊ฒŒ ์•Œ๋งž์€ ์‚ฌ์šฉ๋ฒ•์ด ํ•„์š”ํ•˜๋‹ค.

๋

๋‚™๊ด€์  ์ž ๊ธˆ(Optimistic Lock), ๋น„๊ด€์  ์ž ๊ธˆ(Pessimistic Lock)์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์•˜์Šต๋‹ˆ๋‹ค.
๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๐Ÿ™

Reference

https://velog.io/@lsb156/JPA-Optimistic-Lock-Pessimistic-Lock

http://jaynewho.com/post/43

https://www.youtube.com/watch?v=w6sFR3ZM64c&t=406s

Written on July 2, 2021