๋น„๊ด€์  ๋ฝ vs ๋‚™๊ด€์  ๋ฝ(In JPA)

2024. 11. 28. 04:58ยท๐Ÿ“‚ backend/spring

1. Optimistic Locking in JPA

[1] ๋™์‹œ์„ฑ ์ œ์–ด๋ฅผ ์œ„ํ•œ ๋…ธ๋ ฅ

  1. ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ์ˆ˜์ค€์—์„œ DB์˜ ๋™์‹œ์„ฑ ์ œ์–ด๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค. ํšจ๊ณผ์ ์œผ๋กœ ์˜ค๋ฅ˜ ๋ฐฉ์ง€๊ฐ€ ๊ฐ€๋Šฅํ•œ multiple transaction์„ ํ•ธ๋“ค๋งํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.
  2. ๋Œ€ํ‘œ์ ์ธ ์˜ˆ์‹œ ์ค‘, read ์™€ update ์‚ฌ์ด์˜ ์ผ๊ด€์„ฑ์„ ๋ณด์žฅํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ด ์ƒ๋‹นํžˆ ์ค‘์š”ํ•˜๋‹ค.

 

[2] Optmistic Lock In JPA

  1. JPA์—์„œ ๋‚™๊ด€์  ๋ฝ์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์—”ํ‹ฐํ‹ฐ์— ๋ฒ„์ „์„ ๋ช…์‹œํ•˜๋Š” @Version ์–ด๋…ธํ…Œ์ด์…˜์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค.
  2. Lock Mode์—๋Š” OPTIMISTIC๊ณผ OPTIMISTIC_FORCE_INCREMENT ๋‘ ์ข…๋ฅ˜๊ฐ€ ์žˆ๋‹ค.
    1. OPTIMISTIC: ๋ฒ„์ „ ์†์„ฑ์„ ํฌํ•จํ•˜๋Š” ๋ชจ๋“  ์—”ํ„ฐํ‹ฐ์— ๋Œ€ํ•ด ๋‚™๊ด€์  ์ฝ๊ธฐ ์ž ๊ธˆ์„ ์–ป๋Š”๋‹ค.
      1. READ๋Š” OPTIMISTIC๊ณผ ๊ฐ™์€ ์šฉ๋„๋กœ ์‚ฌ์šฉํ•˜์ง€๋งŒ OPTIMISTIC์„ ์„ ํ˜ธํ•œ๋‹ค.
      2. OPTIMISTIC ์œผ๋กœ ์š”์ฒญํ•  ๊ฒฝ์šฐ, persistence provider์—์„œ dirty read์™€ non-repeatable read๋ฅผ ๋ณดํ˜ธํ•ด์ค€๋‹ค.
    2. OPTIMISTIC_FORCE_INCREMENT๋Š” OPTIMISTIC๊ณผ ๊ฐ™์ง€๋งŒ ์ถ”๊ฐ€์ ์œผ๋กœ ๋ฒ„์ „์„ ์ฆ๊ฐ€์‹œํ‚จ๋‹ค.
      1. WRITE์™€ ๋™์˜์–ด์ง€๋งŒ OPTIMISTIC_FORCE_INCREMENT์„ ์‚ฌ์šฉํ•ด์•ผ ์ข‹๋‹ค.
      2. OPTIMISTIC_INCREMENT์„ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ persistence provider๊ฐ€ OPTIMISTIC_INCREMENT ๊ธฐ๋Šฅ์„ ์•„๋Š” ๊ฒƒ์ด ์ข‹๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค (persistence provider๋Š” ์Šคํ‚ค๋งˆ ์ƒ์„ฑ์„ ์œ„ํ•œ EntityManagerFactory๋ฅผ ์ƒ์„ฑํ•˜๋Š” persistence class ์ด๋ฏ€๋กœ ์—”ํ‹ฐํ‹ฐ๋งค๋‹ˆ์ €์—์„œ ์ปค๋ฐ‹ ๋˜๋Š” ํ”Œ๋Ÿฌ์‹œ ์‹œ์ ์„ ์—ฐ๊ธฐํ•˜๋Š”์ง€์— ๋Œ€ํ•ด ์ง€์ •๋  ์ˆ˜ ์žˆ๋Š” ์žฅ์ ์ด ์žˆ๋‹ค.

 

[3] Optimistic Locking

(1) EntityManager

eneityManager.find(Student.class, studentId, LockModeType.OPTMISTIC);

(2) Query

Query query = entityManager.createQuery("from Student where id = :id");
query.setParameter("id", studentId);
query.setLockMode(LockModeType.OPTIMISTIC_INCREMENT);
query.getResultList()

 

[4] OptimisticLockException

Persistence Provider๊ฐ€ ์—”ํ‹ฐํ‹ฐ์˜ Optimistic Lock ์ถฉ๋Œ์„ ๊ฐ์ง€ํ•˜๋ฉด OptimisticLockException์„ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค. ์ด ์˜ˆ์™ธ๋Š” ์ถฉ๋Œํ•˜๋Š” ์—”ํ‹ฐํ‹ฐ์— ๋Œ€ํ•œ ์ฐธ์กฐ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ๋‹ค.(์›์ธ ์˜ˆ์™ธ์— ๊ด€ํ•œ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•ด์ฃผ๋Š” ๊ฒƒ์œผ๋กœ ์ดํ•ดํ–ˆ๋‹ค.) ํ•˜์ง€๋งŒ PersistenceProvider๊ฐ€ ๋ชจ๋“  ์ƒํ™ฉ์— ๋Œ€ํ•œ ์—”ํ‹ฐํ‹ฐ ์ฐธ์กฐ๋ฅผ ํฌํ•จํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ OptimisticLockException์— ๊ด€ํ•œ ์˜ˆ์™ธ ํ•ธ๋“ค๋ง ๋กœ์ง์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

 

[5] Conclusion

  1. OPTIMISTIC LOCK์€ ์—”ํ‹ฐํ‹ฐ์— ํฌํ•จ๋œ ๋ฒ„์ „ ์†์„ฑ์„ ์ด์šฉํ•ด ์—”ํ‹ฐํ‹ฐ์˜ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ์ˆ˜์ •๊ณผ ์‚ญ์ œ๋กœ ์ธํ•œ ๋ฐ์ดํ„ฐ ๋ฎ์–ด์“ฐ๊ธฐ ๋˜๋Š” ์‚ญ์ œ์— ๊ด€ํ•œ ๋ฌธ์ œ๋ฅผ ๋ณด์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.
  2. ๋Œ€์กฐ์ ์œผ๋กœ PESSIMISTIC LOCK์€ DB LEVEL์—์„œ ์—”ํ‹ฐํ‹ฐ ์ž ๊ธˆ์„ ๊ฑฐ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ DB ๊ต์ฐฉ์ƒํƒœ์— ์ทจ์•ฝํ•˜์ง€ ์•Š๋‹ค.

 

2. Pessimistic Lock In JPA

[1] ๋™์‹œ์„ฑ ์ œ์–ด๋ฅผ ์œ„ํ•œ ๋…ธ๋ ฅ

  • ๋™์‹œ์„ฑ์„ ์ œ์–ดํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ ์ ˆํ•œ ํŠธ๋žœ์žญ์…˜ ๊ฒฉ๋ฆฌ ๋ ˆ๋ฒจ ๋˜๋Š” ๋ฐ์ดํ„ฐ ์ž ๊ธˆ ์„ค์ •์— ๋Œ€ํ•ด ๊ณ ๋ฏผํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค. ํŠธ๋žœ์žญ์…˜ ๊ฒฉ๋ฆฌ ๋ ˆ๋ฒจ์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ปค๋„ฅ์…˜์— ๊ด€ํ•ด ์ •์˜๋œ๋‹ค. ํ•˜์ง€๋งŒ ๊ฒฉ๋ฆฌ ๋ ˆ๋ฒจ์€ ์ปค๋„ฅ์…˜์ด ์ƒ์„ฑ๋˜๋ฉด ํ•œ๋ฒˆ๋งŒ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ปค๋„ฅ์…˜ ๋‚ด์— ๋ชจ๋“  ๋ช…๋ น๋ฌธ์— ์˜ํ–ฅ์„ ๋ฏธ์นœ๋‹ค. ํŠธ๋žœ์žญ์…˜์ด ๊ฐ€์ง€๋Š” ํ•œ๊ณ„๋ฅผ ๋น„๊ด€์  ๋ฝ์„ ํ†ตํ•ด ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค. ๋น„๊ด€์  ๋ฝ์€ ๋ฐ์ดํ„ฐ์˜ ๋ฐฐํƒ€์  ์ ‘๊ทผ์„ ์„ธ๋ถ„ํ™”ํ•˜์—ฌ ํšŒ๋“ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด๋‹ค.
  • ์šฐ๋ฆฌ๊ฐ€ ํš๋“ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฝ์˜ ์ข…๋ฅ˜์—๋Š” Shared Lock ๊ณผ Exlusive Lock์ด ์žˆ๋‹ค. Shared Lock์€ ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ๋ฝ์„ ํš๋“ ํ–ˆ์„ ๋•Œ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์“ธ ์ˆ˜๋Š” ์—†๋‹ค. ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜ ์‚ญ์ œํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ฐฐํƒ€์  ์ž ๊ธˆ์ด ํ•„์š”ํ•˜๋‹ค.

 

[2] Lock Modes

@Lock(LockModeType.PESSIMISTIC_READ)
public Optional<Customer> findById(Long customerId);
  • JPA ๋ช…์„ธ๋Š” 3๊ฐ€์ง€ ๋น„๊ด€์  ๋ฝ์„ ์ •์˜ํ•˜๊ณ  ์žˆ๋‹ค.
    1. PESSIMISTIC_READ : Shared Lock์„ ํš๋“ํ•ด ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž์˜ ์ˆ˜์ •, ์‚ญ์ œ๋ฅผ ๋ง‰๋Š”๋‹ค.
    2. PESSIMISTIC_WRITE : Exclusive Lock์„ ํš๋“ํ•ด ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž์˜ ์กฐํšŒ, ์ˆ˜์ •, ์‚ญ์ œ๋ฅผ ๋ง‰๋Š”๋‹ค.
    3. PESSIMISTIC_FORCE_INCREMENT : PESSIMISTIC_WRITE ์ฒ˜๋Ÿผ ๋™์ž‘ํ•˜๊ณ  ์ถ”๊ฐ€์ ์œผ๋กœ Entity์— version์— ๊ด€ํ•œ ์†์„ฑ์ด ์žˆ์„ ๊ฒฝ์šฐ, ์ถ”๊ฐ€ํ•œ๋‹ค.
  • ์ด ๋ชจ๋‘๋Š” LockModeType ํด๋ž˜์Šค์˜ ์ •์  ๋ฉค๋ฒ„์ด๋ฉฐ ํŠธ๋žœ์žญ์…˜์ด DB ์ž ๊ธˆ์„ ์–ป์„ ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋ฉฐ ์ปค๋ฐ‹, ๋กค๋ฐฑ์ด ๋  ๋•Œ๊นŒ์ง€ ์œ ์ง€๋˜๋Š” ๋ฝ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ ์ž ๊ธˆ๋งŒ ํš๋“ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋ถˆ๊ฐ€๋Šฅ ํ•  ๊ฒฝ์šฐ, PersistenceException์ด ๋ฐœ์ƒํ•œ๋‹ค.

 

  • Pessimistic Lock์— ๊ด€ํ•œ ์˜ˆ์™ธ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.
    • PessimisticLockException : ๋ฝ์„ ํš๋“ํ•˜๊ฑฐ๊ฐ€ Shared Lock์„ Exclusive Lock์„ ๋ณ€ํ™˜ํ•˜๋Š”๋ฐ ์‹คํŒจํ•˜๋Š” ๊ฒฝ์šฐ, ํŠธ๋žœ์žญ์…˜ ์ˆ˜์ค€(transaction-level)์˜ ๋กค๋ฐฑ์ด ๋ฐœ์ƒํ•œ๋‹ค.
    • LockTimeoutException : ์ž ๊ธˆ์„ ํš๋“ํ•˜๊ฑฐ๋‚˜ Shared Lock์„ Exclusive Lock์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š”๋ฐ ์‹œ๊ฐ„์„ ์ดˆ๊ณผํ•˜๋Š” ๊ฒฝ์šฐ ๋ช…๋ น๋ฌธ ์ˆ˜์ค€(statement-level)์˜ ๋กค๋ฐฑ์ด ๋ฐœ์ƒํ•œ๋‹ค.
    • PersitenceException : ์˜์†์„ฑ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ ์˜ˆ์™ธ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. PersistenceException์˜ ํ•˜์œ„ ์˜ˆ์™ธ์ธ NoResultExceptoin, NoUniqueResultException, LockTimeoutException, QueryTimeoutException๋ฅผ ์ œ์™ธํ•œ ์˜ˆ์™ธ๋Š” ํ™œ์„ฑ ํŠธ๋žœ์žญ์…˜์„ ๋กค๋ฐฑํ•˜๋„๋ก ํ‘œ์‹œํ•œ๋‹ค.

 

[3] Lock Scope

@Lock(LockModeType.PESSIMISTIC_READ)
@QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value = "3000")})
public Optional<Customer> findById(Long customerId);
  • Lock Scope parameter๋Š” ๋ฝ์„ ํš๋“ํ•œ ์—”ํ‹ฐํ‹ฐ์˜ ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ž ๊ธˆ์„ ์–ด๋–ป๊ฒŒ ๋‹ค๋ฃฐ์ง€์— ๊ด€ํ•ด ์ •์˜ํ•˜๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ์ด๋‹ค.
    • PersimisticLockScope.NORMAL : LockScope์˜ ๊ธฐ๋ณธ ๊ฐ’์ด๋ฉฐ, ํ•ด๋‹น ์—”ํ‹ฐํ‹ฐ์—๋งŒ ์ž ๊ธˆ์„ ํš๋“ํ•œ๋‹ค. ๋งŒ์•ฝ ์กฐ์ธ ์ƒ์†์„ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ, ์กฐ์ƒ๋„ ์ž ๊ธˆ ๋Œ€์ƒ์— ํฌํ•จ๋œ๋‹ค.
    • PersimisticLockScope.EXTENDED : NORMAL์˜ ๊ธฐ๋Šฅ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์กฐ์ธ ํ…Œ์ด๋ธ”์—์„œ ๊ด€๋ จ ์—”ํ‹ฐํ‹ฐ๋ฅผ ํ•จ๊ป˜ ๋ธ”๋กํ•  ์ˆ˜ ์žˆ๋‹ค. (e.g. @ElementCollection, @OneToOne, @OneToMany, @JoinTable)

 

[4] Lock Timeout

  • TimeOut ์„ค์ •์„ ํ†ตํ•ด ์ž ๊ธˆ์„ ์–ป๊ธฐ ์œ„ํ•œ ๋Œ€๊ธฐ ์‹œ๊ฐ„์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋Œ€๊ธฐ ์‹œ๊ฐ„์˜ ๋‹จ์œ„๋Š” ms์ด๋‹ค.
  • TimeOut ์„ค์ •์„ ์ง€์›ํ•˜์ง€ ์•Š๋Š” DatabasDriver๊ฐ€ ์กด์žฌํ•  ์ˆ˜ ์žˆ์Œ์„ ๋ช…์‹ฌํ•ด์•ผ ํ•œ๋‹ค.

 

References

  • https://www.baeldung.com/jpa-pessimistic-locking
  • https://www.baeldung.com/jpa-optimistic-locking
  • https://www.baeldung.com/java-jpa-transaction-locks

'๐Ÿ“‚ backend > spring' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

์ค‘๋ณต๋˜๋Š” ์Šค์ผ€์ค„๋ง ๋ถ„์‚ฐ๋ฝ์œผ๋กœ ํ•˜๋‚˜๋งŒ ์‹คํ–‰ํ•˜๊ธฐ(w.ShedLock)  (0) 2025.01.16
Spring REST Docs + Swagger UI ๋ฅผ ํ†ตํ•œ API ๋ฌธ์„œํ™”  (0) 2024.12.07
MessageSourceAutoConfiguration ์ฝ”๋“œ ๊ฒ€ํ† ํ•˜๊ธฐ  (0) 2024.11.28
[kurly tech blog] Redisson, Spring AOP ๊ธฐ๋ฐ˜ ๋ถ„์‚ฐ๋ฝ ์ ์šฉ ๋ฐฉ๋ฒ• summary  (0) 2024.11.26
Spring Batch ๊ธฐ๋ฐ˜ ํšŒ์› ์‚ญ์ œ ๋ฐฐ์น˜ ์‚ฝ์งˆ ๊ธฐ๋ก  (0) 2024.09.03
'๐Ÿ“‚ backend/spring' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • ์ค‘๋ณต๋˜๋Š” ์Šค์ผ€์ค„๋ง ๋ถ„์‚ฐ๋ฝ์œผ๋กœ ํ•˜๋‚˜๋งŒ ์‹คํ–‰ํ•˜๊ธฐ(w.ShedLock)
  • Spring REST Docs + Swagger UI ๋ฅผ ํ†ตํ•œ API ๋ฌธ์„œํ™”
  • MessageSourceAutoConfiguration ์ฝ”๋“œ ๊ฒ€ํ† ํ•˜๊ธฐ
  • [kurly tech blog] Redisson, Spring AOP ๊ธฐ๋ฐ˜ ๋ถ„์‚ฐ๋ฝ ์ ์šฉ ๋ฐฉ๋ฒ• summary
cooper25
cooper25
  • cooper25
    dev cooper
    cooper25
  • ์ „์ฒด
    ์˜ค๋Š˜
    ์–ด์ œ
    • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ (84)
      • ๐Ÿ“‚ backend (34)
        • spring (19)
        • architecture (10)
        • test (5)
      • ๐Ÿ“‚ computer-science (5)
      • ๐Ÿ“‚ programming-language (12)
        • java (12)
      • ๐Ÿ“‚ infra (9)
        • mysql (4)
        • redis (2)
        • message-queue (3)
      • ๐Ÿ“‚ cloud (2)
        • aws (2)
      • ๐Ÿ“‚ frontend (1)
        • react (0)
      • ๐Ÿ“‚ education & lecture (16)
        • ์ธํ”„๋ผ ๊ณต๋ฐฉ (11)
        • ํ•ญํ”Œ ๋ฐฑ์—”๋“œ 7๊ธฐ (5)
      • ๐Ÿ“‚ ai (1)
        • claude (1)
      • ๐Ÿ“‚ etc (2)
        • ํšŒ๊ณ  (1)
        • ์ปจํผ๋Ÿฐ์Šค (1)
  • ๋ธ”๋กœ๊ทธ ๋ฉ”๋‰ด

    • ํ™ˆ
    • ํƒœ๊ทธ
    • ๋ฐฉ๋ช…๋ก
  • ๋งํฌ

  • ๊ณต์ง€์‚ฌํ•ญ

  • ์ธ๊ธฐ ๊ธ€

  • ํƒœ๊ทธ

    mysql
    spring camp 2025
    Redisson
    kafka
    spring AOP
    gof
    UUID
    ์ธํ”„๋ผ๊ณต๋ฐฉ
    JPA
    ํ•ญํ•ดํ”Œ๋Ÿฌ์Šค
    spring
    ๊ฐ€์ƒ ๋ฉด์ ‘ ์‚ฌ๋ก€๋กœ ๋ฐฐ์šฐ๋Š” ๋Œ€๊ทœ๋ชจ ์„ค๊ณ„
    AWS
    spring-batch
    nGrinder
    ํšŒ๊ณ 
    ๋ฐ์ดํ„ฐ ์ค‘์‹ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ค๊ณ„
    ์Šคํ”„๋ง์บ ํ”„ ํ›„๊ธฐ
    react
    ๋™์‹œ์„ฑ
  • ์ตœ๊ทผ ๋Œ“๊ธ€

  • ์ตœ๊ทผ ๊ธ€

  • hELLOยท Designed By์ •์ƒ์šฐ.v4.10.6
cooper25
๋น„๊ด€์  ๋ฝ vs ๋‚™๊ด€์  ๋ฝ(In JPA)
์ƒ๋‹จ์œผ๋กœ

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”