동시성 : 하나의 데이터를 여러 사용자가 동시에 수정하거나 읽는 상황
→ 기본적으로 컴퓨터의 연산이 빨라 동시에 같은 데이터에 접근할 일이 거의 없지만, 가끔 여러 사람이 같은 데이터에 접근하는 일이 발생함
경쟁 상태(Race Condition) : 동일 자원을 누가 먼저 처리하느냐에 따라 결과가 달라지고 데이터 일관성이 깨지는 문제가 발생
<aside> 💡
왜 DB에서 막을 수 없을까?
DB는 요청을 독립된 트랜잭션으로 처리하기 때문에, 지금 다른 요청이 같은 데이터를 수정하고 있는지 모름
</aside>
동시성 문제를 해결하는 방법 : 접근 제어(조정)
| 구분 | 비관적 락 | 낙관적 락 |
|---|---|---|
| 접근 방식 | 먼저 잠그고 나중에 작업 | 잠그지 않고 나중에 충돌을 확인 |
| 처리 방식 | 다른 트랜잭션은 대기 상태 | 동시에 접근 가능, 충돌 시 예외 발생 |
| 성능 | 느리지만 안전함 | 빠르지만 충돌 시 재시도 필요 |
| 사용 예 | 민감한 데이터 | |
| (재고 차감, 출금 등) | 엄청 중요하진 않은 데이터 | |
| (게시글 수정, 프로필 변경 등) |
비관적 락(Pessimistic Lock) : “동시에 다른 사용자가 같은 데이터를 수정할 것이다”라고 비관적으로 가정하고 먼저 데이터를 잠그는 방식
→ 한 트랜잭션이 데이터를 수정하는 동안, 다른 요청은 락이 해제될 때까지 대기 상태가 됨
JPA에서 비관적 락 구현 방법 : Repository에 @Lock 어노테이션 사용
public interface AccountRepository extends JpaRepository<Account, Long> {
@Lock(LockModeType.PESSIMISTIC_WRITE) // 쓰기에 대한 Lock 사용
@Query("SELECT a FROM Account a WHERE a.id = :id")
Account findByIdForLOCK(@Param("id") Long id);
}
| 락 타입 | 설명 |
|---|---|
| PESSIMISTIC_READ | 읽기 Lock 사용 |
| PESSIMISTIC_WRITE | 쓰기 Lock 사용 |
비관적 락 사용 시 주의사항