1. Optimistic Locking in JPA
[1] ๋์์ฑ ์ ์ด๋ฅผ ์ํ ๋ ธ๋ ฅ
- ์ํฐํ๋ผ์ด์ฆ ์์ค์์ DB์ ๋์์ฑ ์ ์ด๋ฅผ ๊ด๋ฆฌํ๋ ๊ฒ์ด ์ค์ํ๋ค. ํจ๊ณผ์ ์ผ๋ก ์ค๋ฅ ๋ฐฉ์ง๊ฐ ๊ฐ๋ฅํ multiple transaction์ ํธ๋ค๋งํ ์ ์์ด์ผ ํ๋ค.
- ๋ํ์ ์ธ ์์ ์ค, read ์ update ์ฌ์ด์ ์ผ๊ด์ฑ์ ๋ณด์ฅํด์ผ ํ๋ค๋ ๊ฒ์ด ์๋นํ ์ค์ํ๋ค.
[2] Optmistic Lock In JPA
- JPA์์ ๋๊ด์ ๋ฝ์ ์ฌ์ฉํ๊ธฐ ์ํด์๋ ์ํฐํฐ์ ๋ฒ์ ์ ๋ช ์ํ๋ @Version ์ด๋ ธํ ์ด์ ์ ์ถ๊ฐํด์ผ ํ๋ค.
- Lock Mode์๋ OPTIMISTIC๊ณผ OPTIMISTIC_FORCE_INCREMENT ๋ ์ข
๋ฅ๊ฐ ์๋ค.
- OPTIMISTIC: ๋ฒ์ ์์ฑ์ ํฌํจํ๋ ๋ชจ๋ ์ํฐํฐ์ ๋ํด ๋๊ด์ ์ฝ๊ธฐ ์ ๊ธ์ ์ป๋๋ค.
- READ๋ OPTIMISTIC๊ณผ ๊ฐ์ ์ฉ๋๋ก ์ฌ์ฉํ์ง๋ง OPTIMISTIC์ ์ ํธํ๋ค.
- OPTIMISTIC ์ผ๋ก ์์ฒญํ ๊ฒฝ์ฐ, persistence provider์์ dirty read์ non-repeatable read๋ฅผ ๋ณดํธํด์ค๋ค.
- OPTIMISTIC_FORCE_INCREMENT๋ OPTIMISTIC๊ณผ ๊ฐ์ง๋ง ์ถ๊ฐ์ ์ผ๋ก ๋ฒ์ ์ ์ฆ๊ฐ์ํจ๋ค.
- WRITE์ ๋์์ด์ง๋ง OPTIMISTIC_FORCE_INCREMENT์ ์ฌ์ฉํด์ผ ์ข๋ค.
- OPTIMISTIC_INCREMENT์ ์ฌ์ฉํ ๊ฒฝ์ฐ persistence provider๊ฐ OPTIMISTIC_INCREMENT ๊ธฐ๋ฅ์ ์๋ ๊ฒ์ด ์ข๊ธฐ ๋๋ฌธ์ด๋ค (persistence provider๋ ์คํค๋ง ์์ฑ์ ์ํ EntityManagerFactory๋ฅผ ์์ฑํ๋ persistence class ์ด๋ฏ๋ก ์ํฐํฐ๋งค๋์ ์์ ์ปค๋ฐ ๋๋ ํ๋ฌ์ ์์ ์ ์ฐ๊ธฐํ๋์ง์ ๋ํด ์ง์ ๋ ์ ์๋ ์ฅ์ ์ด ์๋ค.
- OPTIMISTIC: ๋ฒ์ ์์ฑ์ ํฌํจํ๋ ๋ชจ๋ ์ํฐํฐ์ ๋ํด ๋๊ด์ ์ฝ๊ธฐ ์ ๊ธ์ ์ป๋๋ค.
[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
- OPTIMISTIC LOCK์ ์ํฐํฐ์ ํฌํจ๋ ๋ฒ์ ์์ฑ์ ์ด์ฉํด ์ํฐํฐ์ ๋์์ฑ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๋ค. ๊ทธ๋ฌ๋ฏ๋ก ์์ ๊ณผ ์ญ์ ๋ก ์ธํ ๋ฐ์ดํฐ ๋ฎ์ด์ฐ๊ธฐ ๋๋ ์ญ์ ์ ๊ดํ ๋ฌธ์ ๋ฅผ ๋ณด์ฅํ ์ ์๋ค.
- ๋์กฐ์ ์ผ๋ก 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๊ฐ์ง ๋น๊ด์ ๋ฝ์ ์ ์ํ๊ณ ์๋ค.
- PESSIMISTIC_READ : Shared Lock์ ํ๋ํด ๋ค๋ฅธ ์ฌ์ฉ์์ ์์ , ์ญ์ ๋ฅผ ๋ง๋๋ค.
- PESSIMISTIC_WRITE : Exclusive Lock์ ํ๋ํด ๋ค๋ฅธ ์ฌ์ฉ์์ ์กฐํ, ์์ , ์ญ์ ๋ฅผ ๋ง๋๋ค.
- 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
'๐ 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 |
